hiera-eyaml-age 0.1.0 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b410dda98aafc5197a88ce2da1c5b9e946b5262edeed99dc556431d69d8e4801
4
- data.tar.gz: e84d835a8e3f8ab55b2209d51ffc24972b969fed00333797f12dee85c83c7479
3
+ metadata.gz: ac5587ac5f3381c45ce33c739810dde864afc461f0432345c623bc288d76341f
4
+ data.tar.gz: b7303a828c2ab455323f7727c1cbd21baee76be804ab3afaecc4cd3464623cc6
5
5
  SHA512:
6
- metadata.gz: e4de4e92ce526c1bd1385b9bfc0facc9ff94b45f5c672e72959ee623be5e37f09ff469d22eb51b4c044398f236a24b1d3347dcecd57e77394ee73a036fbb8200
7
- data.tar.gz: 450e0669ae45fd070500042c171c89dc042364847890ea28f9ff8541a2cfbb0cb961e5052a77c6d57e56390386cc03d34a65fa30755e806b1a501f0bcb9236d4
6
+ metadata.gz: e5c7b091d59aaa2bb591cdf0f628684b98cab0867fc168a6fe8933003bdab43f0728400879d8bfaf508f9791a22812e3dc47930a73c5822728c3ff799b5569b8
7
+ data.tar.gz: a402ebfbe69fb8e199bc91054ab9a619bd592b05cde1901d496a1201c20361d41c1c2b14789eaa4ebcc76e639c3bb223e15fa2498337bc5c82032513247d0c85
data/.gitignore CHANGED
@@ -1,4 +1,11 @@
1
1
  *.gem
2
2
  *.swp
3
3
  .bundle/
4
+ gem2deb*
5
+ gem2deb*/
6
+ hiera-eyaml-age-*
7
+ hiera-eyaml-age-*/
8
+ hiera-eyaml-age_*
9
+ hiera-eyaml-age_*/
10
+ ruby
4
11
  vendor/
data/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.2] - 2026-05-27
9
+
10
+ ### Fixed
11
+
12
+ - Fix option lookup: rename some option keys that still had `age_` prepended, to avoid double-prefixing by eyaml
13
+ - Override `option()` to correctly apply defined defaults when running on a Puppet server
14
+
15
+ ## [0.2.1] - 2026-05-27
16
+
17
+ ### Fixed
18
+
19
+ - Widen hiera-eyaml dependency range to `>= 4.2.0, < 6.0` to work with both Debian packaging and current gem releases
20
+
21
+ ## [0.2.0] - 2026-05-26
22
+
23
+ ### Added
24
+
25
+ - Manage packaging (gem, deb)
26
+ - Add options to take identity and/or recipients from environment variables instead of files
27
+
28
+ ### Fixed
29
+
30
+ - Handle errors without dumping age's stderr unless asked for
31
+
32
+ ## [0.1.0]
33
+
34
+ ### Added
35
+
36
+ - init
data/Makefile ADDED
@@ -0,0 +1,26 @@
1
+ VERSION := $(shell ruby -r ./lib/hiera/backend/eyaml/encryptors/age/version \
2
+ -e 'puts Hiera::Backend::Eyaml::Encryptors::AgeVersion::VERSION')
3
+ export DEBEMAIL:=network@ias.edu
4
+
5
+
6
+ .PHONY: gem
7
+ gem: hiera-eyaml-age-$(VERSION).gem
8
+
9
+ .PHONY: deb
10
+ deb: hiera-eyaml-age-$(VERSION).gem
11
+ gem2deb --package hiera-eyaml-age hiera-eyaml-age-$(VERSION).gem
12
+
13
+ .PHONY: packages
14
+ packages: deb gem
15
+
16
+ hiera-eyaml-age-$(VERSION).gem:
17
+ gem build hiera-eyaml-age.gemspec
18
+
19
+ .PHONY: clean
20
+ clean:
21
+ rm -rf \
22
+ gem2deb* \
23
+ hiera-eyaml-age-* \
24
+ ruby* \
25
+ hiera-eyaml-age-* \
26
+ hiera-eyaml-age_*
data/README.md CHANGED
@@ -61,6 +61,10 @@ age recipients can be native age public keys (`age1...`) or SSH public keys (`ss
61
61
 
62
62
  Use `eyaml --help` for more, or see the [hiera-eyaml] docs.
63
63
 
64
+ ## Hardware keys and PKCS#11 tokens
65
+
66
+ If your age identity is protected by another factor (e.g. encrypted with a password, or an identity stored with touch required on a hardware security key) be aware that `hiera-eyaml` calls the encryptor once per encrypted value per file. Each call spawns a separate `age` process, which could mean one authorization interaction per encrypted value., depending on your setup. This is a limitation of `hiera-eyaml`'s design, not of `age`.
67
+
64
68
  ### Configuring hiera
65
69
 
66
70
  ```yaml
@@ -71,11 +75,13 @@ hierarchy:
71
75
  - name: "Per-node data"
72
76
  lookup_key: eyaml_lookup_key
73
77
  options:
78
+ age_binary_path: /path/to/age
74
79
  age_identity_file: /opt/puppetlabs/server/data/puppetserver/.age/identity.txt
75
80
  path: "nodes/%{::trusted.certname}.yaml"
76
81
  - name: "Common data"
77
82
  lookup_key: eyaml_lookup_key
78
83
  options:
84
+ age_binary_path: /path/to/age
79
85
  age_identity_file: /opt/puppetlabs/server/data/puppetserver/.age/identity.txt
80
86
  path: "common.yaml"
81
87
  ```
@@ -20,5 +20,5 @@ Gem::Specification.new do |gem|
20
20
  gem.require_paths = ['lib']
21
21
 
22
22
  gem.required_ruby_version = '>= 3.0'
23
- gem.add_dependency('hiera-eyaml', '~> 5.0')
23
+ gem.add_dependency('hiera-eyaml', '>= 4.2.0', '< 6.0')
24
24
  end
@@ -3,7 +3,7 @@ class Hiera
3
3
  module Eyaml
4
4
  module Encryptors
5
5
  module AgeVersion
6
- VERSION = "0.1.0".freeze
6
+ VERSION = "0.2.2".freeze
7
7
  end
8
8
  end
9
9
  end
@@ -13,8 +13,8 @@ class Hiera
13
13
  self.tag = "AGE"
14
14
 
15
15
  self.options = {
16
- age_binary_path: {
17
- desc: "Full path to the age executable",
16
+ binary_path: {
17
+ desc: "Full path to the age executable (use an absolute path in production to avoid PATH-based substitution)",
18
18
  type: :string,
19
19
  default: "age"
20
20
  },
@@ -22,6 +22,10 @@ class Hiera
22
22
  desc: "Path to age identity file for decryption",
23
23
  type: :string
24
24
  },
25
+ identity_env_var: {
26
+ desc: "Name of environment variable containing age identity for decryption",
27
+ type: :string
28
+ },
25
29
  recipients: {
26
30
  desc: "List of recipients (comma separated)",
27
31
  type: :string
@@ -29,9 +33,17 @@ class Hiera
29
33
  recipients_file: {
30
34
  desc: "File containing a list of recipients (one on each line)",
31
35
  type: :string
36
+ },
37
+ recipients_env_var: {
38
+ desc: "Name of environment variable containing age recipients (comma separated)",
39
+ type: :string
32
40
  }
33
41
  }
34
42
 
43
+ def self.option(name)
44
+ super || (self.options[name] || {})[:default]
45
+ end
46
+
35
47
  def self.encrypt(plaintext)
36
48
  recipients = determine_recipients
37
49
  debug("Recipients are #{recipients}")
@@ -46,46 +58,66 @@ class Hiera
46
58
 
47
59
  stdout, stderr, status =
48
60
  Open3.capture3(
49
- option(:age_binary_path),
61
+ option(:binary_path),
50
62
  "--encrypt",
51
63
  *recipient_args,
52
64
  stdin_data: plaintext,
53
65
  binmode: true
54
66
  )
55
67
  unless status.success?
56
- raise RecoverableError, "age encrypt failed: #{stderr.strip}"
68
+ warn("age encrypt failed (run with --trace for details, including errors from age which may be sensitive)")
69
+ debug("age encrypt stderr: #{stderr.strip}")
70
+ raise RecoverableError, "age encrypt failed"
57
71
  end
58
72
 
59
73
  stdout
60
74
  end
61
75
 
62
76
  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"
77
+ env_var = option(:identity_env_var)
78
+
79
+ if env_var
80
+ raise ArgumentError, "env #{env_var} is not set" unless ENV[env_var]
81
+
82
+ # Pass the identity via a pipe rather than a temp file so the key
83
+ # material never touches disk. age's --identity accepts /dev/fd/N.
84
+ # Ruby 2.0+ opens FDs with O_CLOEXEC by default, so we must
85
+ # explicitly preserve the read end across the exec boundary.
86
+ r_fd, w_fd = IO.pipe
87
+ w_fd.write(ENV[env_var])
88
+ w_fd.close
89
+ identity_arg = "/dev/fd/#{r_fd.fileno}"
90
+ extra_opts = { r_fd.fileno => r_fd }
91
+ else
92
+ identity_file = option(:identity_file)
93
+ debug("age identity file is #{identity_file}")
94
+
95
+ if identity_file.nil? || identity_file.empty?
96
+ raise ArgumentError,
97
+ "No age identity file configured, check age_identity_file configuration value is correct"
98
+ end
99
+
100
+ identity_arg = identity_file
101
+ extra_opts = {}
72
102
  end
73
103
 
74
104
  stdout, stderr, status =
75
105
  Open3.capture3(
76
- option(:age_binary_path),
106
+ option(:binary_path),
77
107
  "--decrypt",
78
108
  "--identity",
79
- identity_file,
109
+ identity_arg,
80
110
  stdin_data: ciphertext,
81
- binmode: true
111
+ binmode: true,
112
+ **extra_opts
82
113
  )
83
114
 
115
+ r_fd&.close
116
+
84
117
  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}"
118
+ warn("age decrypt failed (run with --trace for details, including errors from age which may be sensitive)")
119
+ debug("age decrypt stderr: #{stderr.strip}")
120
+ raise StandardError, "age decrypt failed"
89
121
  end
90
122
 
91
123
  stdout
@@ -99,6 +131,14 @@ class Hiera
99
131
  private
100
132
 
101
133
  def determine_recipients
134
+ env_var = option(:recipients_env_var)
135
+ if env_var
136
+ raise ArgumentError, "env #{env_var} is not set" unless ENV[env_var]
137
+
138
+ debug("Using --recipients-env-var option")
139
+ return ENV[env_var].split(",").map(&:strip)
140
+ end
141
+
102
142
  recipient_option = option :recipients
103
143
 
104
144
  unless recipient_option.nil?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiera-eyaml-age
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - IAS Network
@@ -13,16 +13,22 @@ dependencies:
13
13
  name: hiera-eyaml
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '5.0'
18
+ version: 4.2.0
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '6.0'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
22
25
  requirements:
23
- - - "~>"
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 4.2.0
29
+ - - "<"
24
30
  - !ruby/object:Gem::Version
25
- version: '5.0'
31
+ version: '6.0'
26
32
  description: age encryptor for use with hiera-eyaml
27
33
  executables: []
28
34
  extensions: []
@@ -30,8 +36,10 @@ extra_rdoc_files: []
30
36
  files:
31
37
  - ".gitignore"
32
38
  - ".rubocop.yml"
39
+ - CHANGELOG.md
33
40
  - Gemfile
34
41
  - Gemfile.lock
42
+ - Makefile
35
43
  - README.md
36
44
  - Rakefile
37
45
  - hiera-eyaml-age.gemspec