hiera-eyaml-age 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b410dda98aafc5197a88ce2da1c5b9e946b5262edeed99dc556431d69d8e4801
4
+ data.tar.gz: e84d835a8e3f8ab55b2209d51ffc24972b969fed00333797f12dee85c83c7479
5
+ SHA512:
6
+ metadata.gz: e4de4e92ce526c1bd1385b9bfc0facc9ff94b45f5c672e72959ee623be5e37f09ff469d22eb51b4c044398f236a24b1d3347dcecd57e77394ee73a036fbb8200
7
+ data.tar.gz: 450e0669ae45fd070500042c171c89dc042364847890ea28f9ff8541a2cfbb0cb961e5052a77c6d57e56390386cc03d34a65fa30755e806b1a501f0bcb9236d4
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ *.swp
3
+ .bundle/
4
+ vendor/
data/.rubocop.yml ADDED
@@ -0,0 +1,53 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.3
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
6
+ Layout/DotPosition:
7
+ Enabled: false
8
+
9
+ Layout/EndOfLine:
10
+ Enabled: false
11
+
12
+ Layout/LineLength:
13
+ Enabled: false
14
+
15
+ Metrics/AbcSize:
16
+ Enabled: false
17
+
18
+ Metrics/BlockLength:
19
+ Enabled: false
20
+
21
+ Metrics/ClassLength:
22
+ Enabled: false
23
+
24
+ Metrics/CyclomaticComplexity:
25
+ Enabled: false
26
+
27
+ Metrics/MethodLength:
28
+ Enabled: false
29
+
30
+ Metrics/ParameterLists:
31
+ Enabled: false
32
+
33
+ Metrics/PerceivedComplexity:
34
+ Enabled: false
35
+
36
+ Style/ClassAndModuleChildren:
37
+ Enabled: false
38
+
39
+ Style/IfUnlessModifier:
40
+ Enabled: false
41
+
42
+ Style/Documentation:
43
+ Enabled: false
44
+
45
+ Style/FrozenStringLiteralComment:
46
+ Enabled: false
47
+
48
+ Style/StringLiterals:
49
+ Enabled: false
50
+
51
+ # based on https://github.com/voxpupuli/modulesync_config/issues/168
52
+ Style/RegexpLiteral:
53
+ EnforcedStyle: percent_r
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source ENV['GEM_SOURCE'] || 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake', require: false
7
+ gem 'rubocop', require: false
8
+ gem 'syntax', require: false
9
+ gem 'syntax_tree', require: false
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,69 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hiera-eyaml-age (0.1.0)
5
+ hiera-eyaml (~> 5.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.3)
11
+ base64 (0.3.0)
12
+ hiera-eyaml (5.0.1)
13
+ base64 (~> 0.1)
14
+ highline (>= 2.1, < 4)
15
+ optimist (~> 3.1)
16
+ highline (3.1.2)
17
+ reline
18
+ io-console (0.8.2)
19
+ json (2.19.5)
20
+ language_server-protocol (3.17.0.5)
21
+ lint_roller (1.1.0)
22
+ optimist (3.2.1)
23
+ parallel (2.1.0)
24
+ parser (3.3.11.1)
25
+ ast (~> 2.4.1)
26
+ racc
27
+ prettier_print (1.2.1)
28
+ prism (1.9.0)
29
+ racc (1.8.1)
30
+ rainbow (3.1.1)
31
+ rake (13.4.2)
32
+ regexp_parser (2.12.0)
33
+ reline (0.6.3)
34
+ io-console (~> 0.5)
35
+ rubocop (1.86.2)
36
+ json (~> 2.3)
37
+ language_server-protocol (~> 3.17.0.2)
38
+ lint_roller (~> 1.1.0)
39
+ parallel (>= 1.10)
40
+ parser (>= 3.3.0.2)
41
+ rainbow (>= 2.2.2, < 4.0)
42
+ regexp_parser (>= 2.9.3, < 3.0)
43
+ rubocop-ast (>= 1.49.0, < 2.0)
44
+ ruby-progressbar (~> 1.7)
45
+ unicode-display_width (>= 2.4.0, < 4.0)
46
+ rubocop-ast (1.49.1)
47
+ parser (>= 3.3.7.2)
48
+ prism (~> 1.7)
49
+ ruby-progressbar (1.13.0)
50
+ syntax (1.2.2)
51
+ syntax_tree (6.3.0)
52
+ prettier_print (>= 1.2.0)
53
+ unicode-display_width (3.2.0)
54
+ unicode-emoji (~> 4.1)
55
+ unicode-emoji (4.2.0)
56
+
57
+ PLATFORMS
58
+ ruby
59
+ x86_64-linux-gnu
60
+
61
+ DEPENDENCIES
62
+ hiera-eyaml-age!
63
+ rake
64
+ rubocop
65
+ syntax
66
+ syntax_tree
67
+
68
+ BUNDLED WITH
69
+ 2.6.7
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ hiera-eyaml-age
2
+ ===============
3
+
4
+ age encryption backend for [hiera-eyaml].
5
+
6
+ # Motivation
7
+
8
+ The default PKCS#7 encryption scheme used by `hiera-eyaml` works, but relies upon just a single key.
9
+
10
+ A solution that allows each team member and Puppet Server to hold their own keys allows for easier rotation.
11
+
12
+ [hiera-eyaml-gpg] supports each team member using their own keys, but.... it is GPG. Many may not be keen to get a degree in keyring management just to edit hieradata.
13
+
14
+ [age] supports encrypting to many with individual keys as well, but without the hassle. It offers meaningfully stronger encryption, even introducing post-quantum resistance since v1.3.0.
15
+
16
+ # Requirements
17
+
18
+ age [installed] in your `$PATH`.
19
+
20
+ # Install
21
+
22
+ ```sh
23
+ gem install hiera-eyaml-age
24
+ ```
25
+
26
+ # Configuration
27
+
28
+ ```sh
29
+ # ~/.eyaml/config.yaml
30
+ age_identity_file: '/path/to/your/identity/file'
31
+ age_recipients: '<age_pubkey1>,<age_pubkey2>,...'
32
+ # age_recipients_file: '/path/to/recipients/file/pubkeys/one/per/line.txt'
33
+ # age_binary_path: '/optional/path/directly/to/age'
34
+ ```
35
+
36
+ # Usage
37
+
38
+ ## Encrypting and editing encrypted data
39
+
40
+ It is recommended to configure `hiera-eyaml` as above to avoid having to pass the necessary arguments each time.
41
+
42
+ The usual workflow can be as simple as `eyaml edit` and following the instructions at the top of the file:
43
+
44
+ ```sh
45
+ eyaml edit /path/to/hieradata/file.yaml
46
+ ```
47
+
48
+ Or more manually, create encrypted ``hiera-eyaml`` blocks encrypted with age:
49
+
50
+ ```sh
51
+ eyaml encrypt --encrypt-method age --string "My string to encrypt" --age-recipients age126amywumzxvz2d9umnv3796tfsy044ww7pe7rwampammswl0n4rqv4c557,age162268ddynmjurmd7z628rctuh4qfavd84c62sjxhnmq7sw06c3lsmyetzf
52
+ ```
53
+
54
+ Or pass a file containing a list of recipients (one per line, `#` comments ignored):
55
+
56
+ ```sh
57
+ eyaml encrypt --encrypt-method age --string "My string to encrypt" --age-recipients-file /path/to/youur/recipients/file
58
+ ```
59
+
60
+ age recipients can be native age public keys (`age1...`) or SSH public keys (`ssh-ed25519 ...`, `ssh-rsa ...`).
61
+
62
+ Use `eyaml --help` for more, or see the [hiera-eyaml] docs.
63
+
64
+ ### Configuring hiera
65
+
66
+ ```yaml
67
+ ---
68
+ version: 5
69
+ defaults:
70
+ hierarchy:
71
+ - name: "Per-node data"
72
+ lookup_key: eyaml_lookup_key
73
+ options:
74
+ age_identity_file: /opt/puppetlabs/server/data/puppetserver/.age/identity.txt
75
+ path: "nodes/%{::trusted.certname}.yaml"
76
+ - name: "Common data"
77
+ lookup_key: eyaml_lookup_key
78
+ options:
79
+ age_identity_file: /opt/puppetlabs/server/data/puppetserver/.age/identity.txt
80
+ path: "common.yaml"
81
+ ```
82
+
83
+ ### Installing on Puppet server
84
+
85
+ ```sh
86
+ # Puppet agent and Server have separate Ruby environments
87
+ /opt/puppetlabs/puppet/bin/gem install hiera-eyaml-age
88
+ /opt/puppetlabs/server/bin/puppetserver gem install hiera-eyaml-age
89
+ ```
90
+
91
+ [age]: https://age-encryption.org/
92
+ [hiera-eyaml-gpg]: https://github.com/voxpupuli/hiera-eyaml-gpg
93
+ [hiera-eyaml]: https://github.com/voxpupuli/hiera-eyaml
94
+ [installed]: https://age-encryption.org/#installation
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rubocop/rake_task'
3
+
4
+ desc 'Run RuboCop on the lib directory'
5
+ RuboCop::RakeTask.new(:rubocop) do |task|
6
+ task.patterns = ['lib/**/*.rb']
7
+ end
8
+
9
+ task test: %w[clean rubocop]
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'hiera/backend/eyaml/encryptors/age/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'hiera-eyaml-age'
7
+ gem.version = Hiera::Backend::Eyaml::Encryptors::AgeVersion::VERSION
8
+ gem.description = 'age encryptor for use with hiera-eyaml'
9
+ gem.summary = 'Encryption plugin for hiera-eyaml backend for Hiera'
10
+ gem.authors = ['IAS Network']
11
+ gem.license = 'MIT'
12
+ gem.homepage = 'https://github.com/theias/hiera-eyaml-age'
13
+ gem.metadata = {
14
+ 'source_code_uri' => 'https://github.com/theias/hiera-eyaml-age',
15
+ 'changelog_uri' => 'https://github.com/theias/hiera-eyaml-age/blob/main/CHANGELOG.md',
16
+ 'bug_tracker_uri' => 'https://github.com/theias/hiera-eyaml-age/issues',
17
+ }
18
+
19
+ gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
20
+ gem.require_paths = ['lib']
21
+
22
+ gem.required_ruby_version = '>= 3.0'
23
+ gem.add_dependency('hiera-eyaml', '~> 5.0')
24
+ end
@@ -0,0 +1,3 @@
1
+ require "hiera/backend/eyaml/encryptors/age"
2
+
3
+ Hiera::Backend::Eyaml::Encryptors::Age.register
@@ -0,0 +1,11 @@
1
+ class Hiera
2
+ module Backend
3
+ module Eyaml
4
+ module Encryptors
5
+ module AgeVersion
6
+ VERSION = "0.1.0".freeze
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,125 @@
1
+ require "open3"
2
+ require "hiera/backend/eyaml/encryptor"
3
+ require "hiera/backend/eyaml/utils"
4
+ require "hiera/backend/eyaml/options"
5
+ require "hiera/backend/eyaml/encryptors/age/version"
6
+
7
+ class Hiera
8
+ module Backend
9
+ module Eyaml
10
+ module Encryptors
11
+ class Age < Encryptor
12
+ VERSION = Hiera::Backend::Eyaml::Encryptors::AgeVersion::VERSION
13
+ self.tag = "AGE"
14
+
15
+ self.options = {
16
+ age_binary_path: {
17
+ desc: "Full path to the age executable",
18
+ type: :string,
19
+ default: "age"
20
+ },
21
+ identity_file: {
22
+ desc: "Path to age identity file for decryption",
23
+ type: :string
24
+ },
25
+ recipients: {
26
+ desc: "List of recipients (comma separated)",
27
+ type: :string
28
+ },
29
+ recipients_file: {
30
+ desc: "File containing a list of recipients (one on each line)",
31
+ type: :string
32
+ }
33
+ }
34
+
35
+ def self.encrypt(plaintext)
36
+ recipients = determine_recipients
37
+ debug("Recipients are #{recipients}")
38
+
39
+ if recipients.empty?
40
+ raise RecoverableError,
41
+ "No recipients provided, don't know who to encrypt to"
42
+ end
43
+
44
+ recipient_args =
45
+ recipients.flat_map { |recipient| ["-r", recipient] }
46
+
47
+ stdout, stderr, status =
48
+ Open3.capture3(
49
+ option(:age_binary_path),
50
+ "--encrypt",
51
+ *recipient_args,
52
+ stdin_data: plaintext,
53
+ binmode: true
54
+ )
55
+ unless status.success?
56
+ raise RecoverableError, "age encrypt failed: #{stderr.strip}"
57
+ end
58
+
59
+ stdout
60
+ end
61
+
62
+ def self.decrypt(ciphertext)
63
+ identity_file = option(:identity_file)
64
+ debug("age identity file is #{identity_file}")
65
+
66
+ if identity_file.nil? || identity_file.empty?
67
+ raise ArgumentError,
68
+ "No age identity file configured, check age_identity_file configuration value is correct"
69
+ elsif !File.exist?(identity_file)
70
+ raise ArgumentError,
71
+ "Configured age identity file #{identity_file} doesn't exist, check age_identity_file configuration value is correct"
72
+ end
73
+
74
+ stdout, stderr, status =
75
+ Open3.capture3(
76
+ option(:age_binary_path),
77
+ "--decrypt",
78
+ "--identity",
79
+ identity_file,
80
+ stdin_data: ciphertext,
81
+ binmode: true
82
+ )
83
+
84
+ unless status.success?
85
+ warn(
86
+ "Fatal: Failed to decrypt ciphertext (check settings and that you are a recipient)"
87
+ )
88
+ raise StandardError, "age decrypt failed: #{stderr.strip}"
89
+ end
90
+
91
+ stdout
92
+ end
93
+
94
+ def self.create_keys
95
+ warn "The age encryptor does not support creation of keys, use the age command line tools instead"
96
+ end
97
+
98
+ class << self
99
+ private
100
+
101
+ def determine_recipients
102
+ recipient_option = option :recipients
103
+
104
+ unless recipient_option.nil?
105
+ debug("Using --recipients option")
106
+ return recipient_option.split(",").map(&:strip)
107
+ end
108
+
109
+ recipients_file_option = option :recipients_file
110
+ return [] if recipients_file_option.nil?
111
+
112
+ debug("Using --recipients-file option")
113
+ File
114
+ .readlines(recipients_file_option)
115
+ .map do |line|
116
+ line.strip unless line.start_with?("#") || line.strip.empty?
117
+ end
118
+ .compact
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hiera-eyaml-age
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - IAS Network
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: hiera-eyaml
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '5.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '5.0'
26
+ description: age encryptor for use with hiera-eyaml
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files: []
30
+ files:
31
+ - ".gitignore"
32
+ - ".rubocop.yml"
33
+ - Gemfile
34
+ - Gemfile.lock
35
+ - README.md
36
+ - Rakefile
37
+ - hiera-eyaml-age.gemspec
38
+ - lib/hiera/backend/eyaml/encryptors/age.rb
39
+ - lib/hiera/backend/eyaml/encryptors/age/eyaml_init.rb
40
+ - lib/hiera/backend/eyaml/encryptors/age/version.rb
41
+ homepage: https://github.com/theias/hiera-eyaml-age
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ source_code_uri: https://github.com/theias/hiera-eyaml-age
46
+ changelog_uri: https://github.com/theias/hiera-eyaml-age/blob/main/CHANGELOG.md
47
+ bug_tracker_uri: https://github.com/theias/hiera-eyaml-age/issues
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.6.7
63
+ specification_version: 4
64
+ summary: Encryption plugin for hiera-eyaml backend for Hiera
65
+ test_files: []