rails_outofband_keys 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +49 -0
- data/lib/rails_outofband_keys/config.rb +14 -0
- data/lib/rails_outofband_keys/errors.rb +12 -0
- data/lib/rails_outofband_keys/key_resolver.rb +74 -0
- data/lib/rails_outofband_keys/railtie.rb +39 -0
- data/lib/rails_outofband_keys/version.rb +5 -0
- data/lib/rails_outofband_keys.rb +7 -0
- metadata +79 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c028a4ebdbf7196c3cdaa3279dfda0dd8d5d75d25a9b662c847847d650087b1d
|
|
4
|
+
data.tar.gz: 6d393b4056c6e6bfd9b63f7bdbb7dbba10a29544ca833a7e09109d71498f59c1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8d0f2b467ced1b33e8e139843413f4e1f0c21e524a73eb41985dba3c75091a9d8818bd87976b21cab592ca4f5d325e426991720ef7d3cd62b36347ab96597202
|
|
7
|
+
data.tar.gz: 642e1b15c124d6dc4fee45991c69fee2b36ef486f6428a61b7844b371350c1b9de55b07f70d8b70e4dfd11a56ae0e5ef4ca30ebee770f65688cdaa7cab10f485
|
data/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# rails_outofband_keys
|
|
2
|
+
|
|
3
|
+
`rails_outofband_keys` is a Rails plugin that changes **how Rails finds your credentials key files** (e.g., `production.key` or `master.key`). It allows you to keep these sensitive keys **outside of your project directory and git tree** (e.g., in `~/.config/`).
|
|
4
|
+
|
|
5
|
+
It does **not** replace Rails credentials, change where `credentials.yml.enc` lives, or alter how encryption works. It only dynamically configures `config.credentials.key_path` during the boot process.
|
|
6
|
+
|
|
7
|
+
## Resolution Order
|
|
8
|
+
|
|
9
|
+
1. If `RAILS_MASTER_KEY` is set in the environment, Rails uses it (this gem does nothing).
|
|
10
|
+
2. If `RAILS_CREDENTIALS_KEY_DIR` is set, it is used as the base directory for the app.
|
|
11
|
+
3. If `RAILS_OUTOFBAND_BASE_DIR` is set, it is used as the global base directory.
|
|
12
|
+
4. Otherwise, the gem fallbacks to OS defaults:
|
|
13
|
+
- **Linux/macOS**: XDG config directory (`~/.config` fallback)
|
|
14
|
+
- **Windows**: `%AppData%`
|
|
15
|
+
|
|
16
|
+
The final path is constructed as:
|
|
17
|
+
`base_directory / root_subdir / credentials_subdir / <environment>.key`
|
|
18
|
+
`base_directory / root_subdir / credentials_subdir / master.key`
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
Because Rails initializes credentials very early (especially for CLI tools like `credentials:edit`), this gem is configured via a YAML file located at `config/rails_outofband_keys.yml`.
|
|
23
|
+
|
|
24
|
+
### Example config/rails_outofband_keys.yml
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
# The sub-folder for your application or organization
|
|
28
|
+
root_subdir: "my_org/my_app"
|
|
29
|
+
|
|
30
|
+
# The subdirectory where keys are stored (defaults to "credentials")
|
|
31
|
+
# Set to null if keys live directly in the root_subdir
|
|
32
|
+
credentials_subdir: "credentials"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Permissions
|
|
36
|
+
|
|
37
|
+
On Unix-like systems, key files **must** have secure permissions. They must be owner-readable and **must not** be accessible by group or others (e.g., mode `0600` or `0400`). The app will raise an `InsecureKeyPermissionsError` and refuse to boot if permissions are too open.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Add the gem to your Gemfile:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
gem "rails_outofband_keys", git: "git@github.com:lholden/rails_outofband_keys.git", tag: "v0.1.1"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsOutofbandKeys
|
|
4
|
+
# Configuration for RailsOutofbandKeys.
|
|
5
|
+
class Config
|
|
6
|
+
attr_accessor :root_subdir, :credentials_subdir, :key_dir_env
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@root_subdir = nil
|
|
10
|
+
@credentials_subdir = "credentials"
|
|
11
|
+
@key_dir_env = "RAILS_CREDENTIALS_KEY_DIR"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsOutofbandKeys
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
|
|
6
|
+
# Error raised when key file permissions are too open.
|
|
7
|
+
class InsecureKeyPermissionsError < Error
|
|
8
|
+
def initialize(path, mode)
|
|
9
|
+
super("Insecure permissions on #{path} (#{mode}); expected 0600 or 0400")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "xdg"
|
|
6
|
+
|
|
7
|
+
module RailsOutofbandKeys
|
|
8
|
+
# Resolves the path to the credentials key file.
|
|
9
|
+
class KeyResolver
|
|
10
|
+
def initialize(config:, rails_env:, app_name:)
|
|
11
|
+
@config = config
|
|
12
|
+
@rails_env = rails_env
|
|
13
|
+
@app_name = app_name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def resolve_key_path
|
|
17
|
+
return nil if ENV["RAILS_MASTER_KEY"] && !ENV["RAILS_MASTER_KEY"].empty?
|
|
18
|
+
|
|
19
|
+
key = find_key_in_resolved_dir
|
|
20
|
+
enforce_permissions!(key) if key
|
|
21
|
+
key&.to_s
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def find_key_in_resolved_dir
|
|
27
|
+
dir = resolved_key_dir
|
|
28
|
+
env_key = dir.join("#{@rails_env}.key")
|
|
29
|
+
return env_key if env_key.file?
|
|
30
|
+
|
|
31
|
+
master_key = dir.join("master.key")
|
|
32
|
+
master_key.file? ? master_key : nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def resolved_key_dir
|
|
36
|
+
base = resolve_base_dir
|
|
37
|
+
root = @config.root_subdir || @app_name
|
|
38
|
+
|
|
39
|
+
path_parts = [base, root]
|
|
40
|
+
path_parts << @config.credentials_subdir if @config.credentials_subdir
|
|
41
|
+
|
|
42
|
+
Pathname.new(File.join(*path_parts))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
public
|
|
46
|
+
|
|
47
|
+
def resolve_base_dir
|
|
48
|
+
# Specific application override
|
|
49
|
+
override = ENV[@config.key_dir_env].to_s.strip
|
|
50
|
+
return override unless override.empty?
|
|
51
|
+
|
|
52
|
+
# Global base override
|
|
53
|
+
global_base = ENV["RAILS_OUTOFBAND_BASE_DIR"].to_s.strip
|
|
54
|
+
return global_base unless global_base.empty?
|
|
55
|
+
|
|
56
|
+
return ENV.fetch("APPDATA") if Gem.win_platform?
|
|
57
|
+
|
|
58
|
+
XDG.new.config_home.to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def enforce_permissions!(path)
|
|
62
|
+
return if Gem.win_platform?
|
|
63
|
+
|
|
64
|
+
mode = File.stat(path).mode & 0o777
|
|
65
|
+
|
|
66
|
+
owner_only = mode.nobits?(0o077)
|
|
67
|
+
readable = mode.anybits?(0o400)
|
|
68
|
+
|
|
69
|
+
return if owner_only && readable
|
|
70
|
+
|
|
71
|
+
raise InsecureKeyPermissionsError.new(path, format("0%o", mode))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/railtie"
|
|
4
|
+
require "yaml"
|
|
5
|
+
|
|
6
|
+
module RailsOutofbandKeys
|
|
7
|
+
# Railtie to integrate with Rails and automatically set key_path.
|
|
8
|
+
class Railtie < Rails::Railtie
|
|
9
|
+
config.rails_outofband_keys = RailsOutofbandKeys::Config.new
|
|
10
|
+
|
|
11
|
+
config.before_configuration do |app|
|
|
12
|
+
# Load file-based configuration.
|
|
13
|
+
config_file = File.join(Dir.getwd, "config", "rails_outofband_keys.yml")
|
|
14
|
+
|
|
15
|
+
if File.exist?(config_file)
|
|
16
|
+
external_config = YAML.load_file(config_file)
|
|
17
|
+
app.config.rails_outofband_keys.root_subdir = external_config["root_subdir"]
|
|
18
|
+
app.config.rails_outofband_keys.credentials_subdir = external_config.fetch("credentials_subdir", "credentials")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Identify the app name for path resolution.
|
|
22
|
+
app_name = app.railtie_name.to_s.underscore.sub(/_application$/, "")
|
|
23
|
+
|
|
24
|
+
resolver = KeyResolver.new(
|
|
25
|
+
config: app.config.rails_outofband_keys,
|
|
26
|
+
rails_env: Rails.env,
|
|
27
|
+
app_name: app_name
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
key_path = resolver.resolve_key_path
|
|
31
|
+
if key_path
|
|
32
|
+
app.config.credentials.key_path = key_path
|
|
33
|
+
|
|
34
|
+
# Clear any early-cached credentials object to ensure the new path is used.
|
|
35
|
+
app.remove_instance_variable(:@credentials) if app.instance_variable_defined?(:@credentials)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "rails_outofband_keys/version"
|
|
4
|
+
require_relative "rails_outofband_keys/errors"
|
|
5
|
+
require_relative "rails_outofband_keys/config"
|
|
6
|
+
require_relative "rails_outofband_keys/key_resolver"
|
|
7
|
+
require_relative "rails_outofband_keys/railtie"
|
metadata
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails_outofband_keys
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Lori Holden
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: railties
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '6.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '6.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: xdg
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.2'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.2'
|
|
40
|
+
description: |
|
|
41
|
+
Configures Rails credentials key_path to load environment/master key files
|
|
42
|
+
from an out-of-band directory (XDG on Unix/MacOS, AppData on Windows).
|
|
43
|
+
email:
|
|
44
|
+
- git@loriholden.com
|
|
45
|
+
executables: []
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- README.md
|
|
50
|
+
- lib/rails_outofband_keys.rb
|
|
51
|
+
- lib/rails_outofband_keys/config.rb
|
|
52
|
+
- lib/rails_outofband_keys/errors.rb
|
|
53
|
+
- lib/rails_outofband_keys/key_resolver.rb
|
|
54
|
+
- lib/rails_outofband_keys/railtie.rb
|
|
55
|
+
- lib/rails_outofband_keys/version.rb
|
|
56
|
+
homepage: https://github.com/lholden/rails_outofband_keys
|
|
57
|
+
licenses:
|
|
58
|
+
- MIT
|
|
59
|
+
metadata:
|
|
60
|
+
rubygems_mfa_required: 'true'
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 4.0.2
|
|
76
|
+
specification_version: 4
|
|
77
|
+
summary: Resolve Rails credentials key files outside the project tree (XDG/AppData
|
|
78
|
+
+ overrides).
|
|
79
|
+
test_files: []
|