acmesmith 0.10.0 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 39060c7505c4a73bfccf496d1015c69573e247b7
4
- data.tar.gz: f021fc666dee39ce983143b8b42c6d89fe10e336
3
+ metadata.gz: bce001c8eca147fba2d1d2e0b43d30ebd175f096
4
+ data.tar.gz: 65fb44fdf5367fa3e6c66ecb837fd3119f07db76
5
5
  SHA512:
6
- metadata.gz: 07ee7ce1383349bd7fbc93d78fe97bca3d9407df833c3d7f299d5fd17ef1307118f5e50f8c28523a131cc9756cfb858d9aa465a43850d6f86a723b8f06515fdc
7
- data.tar.gz: be76cdfe37a4988c9dfdb1db3d3fb49bc16ba7fe719ae7ad588f22a1f636f74b19f9f5383464d52128055bcc83e9de7102528ba04b2df98b887b2deb157d6176
6
+ metadata.gz: a544bb8d9ee438806215471846bd71dd34fcd3dc0cdd38d15a130292d255c1f221492c1c129bcdb5906ac8afc5819b161296dd0b64607ad36149966f7cf23d7e
7
+ data.tar.gz: ecc46f9cc09ec3630d14a3052b43b51659fdaba8716e43095bc578326e7e5fc99174da54b26d80abc1579b8bb7c35e991e405a5238a38fd7c805ca985b9fa630
data/README.md CHANGED
@@ -62,6 +62,14 @@ $ acmesmith save-pkcs12 COMMON_NAME --output=PATH # Save certificate and p
62
62
  $ acmesmith autorenew [-d DAYS] # Renew certificates which being expired soon
63
63
  ```
64
64
 
65
+ ```
66
+ # Save (or update) certificate files and key in a one command
67
+ $ acmesmith save COMMON_NAME \
68
+ --version-file=/tmp/cert.txt # Path to save a certificate version for following run
69
+ --key-file=/tmp/cert.key # Path to save a key
70
+ --fullchain-file=/tmp/cert.pem # Path to save a certficiate and its chain (concatenated)
71
+ ```
72
+
65
73
  See `acmesmith help [subcommand]` for more help.
66
74
 
67
75
  ## Configuration
data/docs/vendor/aws.md CHANGED
@@ -103,4 +103,20 @@ Be sure to replace `{S3-REGION}` and `{YOUR-AWS-ACCOUNT-ID}` before applying it.
103
103
  }
104
104
  ```
105
105
 
106
+ #### Policy for ACM post issuing hook
107
+
108
+ ``` json
109
+ {
110
+ "Version": "2012-10-17",
111
+ "Statement": [
112
+ {
113
+ "Effect": "Allow",
114
+ "Action": ["acm:ImportCertificate", "acm:AddTagsToCertificate"],
115
+ "Resource": ["*"]
116
+ }
117
+ ]
118
+ }
119
+ ```
120
+
121
+ Optionally you can limit resource to certificate ARN(s).
106
122
 
@@ -1,6 +1,8 @@
1
1
  require 'acmesmith/account_key'
2
2
  require 'acmesmith/certificate'
3
3
 
4
+ require 'acmesmith/save_certificate_service'
5
+
4
6
  require 'acme-client'
5
7
 
6
8
  module Acmesmith
@@ -146,10 +148,17 @@ module Acmesmith
146
148
  certs
147
149
  end
148
150
 
149
- def save_certificate(common_name, version: 'current', mode: '0600', output:)
151
+ def save_certificate(common_name, version: 'current', mode: '0600', output:, type: 'fullchain')
150
152
  cert = storage.get_certificate(common_name, version: version)
151
153
  File.open(output, 'w', mode.to_i(8)) do |f|
152
- f.puts(cert.fullchain)
154
+ case type
155
+ when 'certificate'
156
+ f.puts cert.certificate.to_pem
157
+ when 'chain'
158
+ f.puts cert.chain
159
+ when 'fullchain'
160
+ f.puts cert.fullchain
161
+ end
153
162
  end
154
163
  end
155
164
 
@@ -178,6 +187,13 @@ module Acmesmith
178
187
  end
179
188
  end
180
189
 
190
+ def save(common_name, version: 'current', **kwargs)
191
+ cert = storage.get_certificate(common_name, version: version)
192
+ cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
193
+
194
+ SaveCertificateService.new(cert, **kwargs).perform!
195
+ end
196
+
181
197
  def autorenew(days: 7, common_names: nil)
182
198
  (common_names || storage.list_certificates).each do |cn|
183
199
  puts "=> #{cn}"
@@ -6,7 +6,7 @@ require 'acmesmith/client'
6
6
  module Acmesmith
7
7
  class Command < Thor
8
8
  class_option :config, default: './acmesmith.yml', aliases: %w(-c)
9
- class_option :passphrase_from_env, type: :boolean, aliases: %w(-E), default: false, desc: 'Read $ACMESMITH_ACCOUNT_KEY_PASSPHRASE and $ACMESMITH_CERTIFICATE_KEY_PASSPHRASE for passphrases'
9
+ class_option :passphrase_from_env, type: :boolean, aliases: %w(-E), default: nil, desc: 'Read $ACMESMITH_ACCOUNT_KEY_PASSPHRASE and $ACMESMITH_CERTIFICATE_KEY_PASSPHRASE for passphrases'
10
10
 
11
11
  desc "register CONTACT", "Create account key (contact e.g. mailto:xxx@example.org)"
12
12
  def register(contact)
@@ -57,10 +57,11 @@ module Acmesmith
57
57
 
58
58
  desc 'save-certificate COMMON_NAME', 'Save certificate to a file'
59
59
  method_option :version, type: :string, default: 'current'
60
+ method_option :type, type: :string, enum: %w(certificate chain fullchain), default: 'fullchain'
60
61
  method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
61
62
  method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
62
63
  def save_certificate(common_name)
63
- client.save_certificate(common_name, version: options[:version], mode: options[:mode], output: options[:output])
64
+ client.save_certificate(common_name, version: options[:version], mode: options[:mode], output: options[:output], type: options[:type])
64
65
  end
65
66
 
66
67
  desc "show-private-key COMMON_NAME", "show private key"
@@ -78,6 +79,32 @@ module Acmesmith
78
79
  client.save_private_key(common_name, version: options[:version], mode: options[:mode], output: options[:output])
79
80
  end
80
81
 
82
+ desc 'save COMMON_NAME', 'Save (or update) certificate and key files.'
83
+ method_option :version, type: :string, default: 'current'
84
+ method_option :key_mode, type: :string, default: '0600', desc: 'Mode (permission) of the key file on create'
85
+ method_option :certificate_mode, type: :string, default: '0644', desc: 'Mode (permission) of the certificate files on create'
86
+ method_option :version_file, type: :string, required: false, banner: 'PATH', desc: 'Path to save a certificate version for following run (optional)'
87
+ method_option :key_file, type: :string, required: false, banner: 'PATH', desc: 'Path to save a key'
88
+ method_option :fullchain_file, type: :string, required: false , banner: 'PATH', desc: 'Path to save a certficiate and its chain (concatenated)'
89
+ method_option :chain_file, type: :string, required: false , banner: 'PATH', desc: 'Path to save a certificate chain (root and intermediate CA)'
90
+ method_option :certificate_file, type: :string, required: false, banner: 'PATH', desc: 'Path to save a certficiate'
91
+ method_option :atomic, type: :boolean, default: true, desc: 'Enable atomic file update with rename(2)'
92
+ def save(common_name)
93
+ client.save(
94
+ common_name,
95
+ version: options[:version],
96
+ key_mode: options[:key_mode],
97
+ certificate_mode: options[:certificate_mode],
98
+ version_file: options[:version_file],
99
+ key_file: options[:key_file],
100
+ fullchain_file: options[:fullchain_file],
101
+ chain_file: options[:chain_file],
102
+ certificate_file: options[:certificate_file],
103
+ atomic: options[:atomic],
104
+ verbose: true,
105
+ )
106
+ end
107
+
81
108
  desc 'save-pkcs12 COMMON_NAME', 'Save ceriticate and private key to .p12 file'
82
109
  method_option :version, type: :string, default: 'current'
83
110
  method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
@@ -0,0 +1,64 @@
1
+ module Acmesmith
2
+ class SaveCertificateService
3
+ def initialize(cert, key_mode: '0600', certificate_mode: '0644', version_file: nil, key_file: nil, fullchain_file: nil, chain_file: nil, certificate_file: nil, atomic: true, verbose: false)
4
+ @cert = cert
5
+ @key_mode = key_mode
6
+ @certificate_mode = certificate_mode
7
+ @version_file = version_file
8
+ @key_file = key_file
9
+ @fullchain_file = fullchain_file
10
+ @chain_file = chain_file
11
+ @certificate_file = certificate_file
12
+ @atomic = atomic
13
+ @verbose = verbose
14
+ end
15
+
16
+ attr_reader :cert
17
+ attr_reader :key_mode, :certificate_mode
18
+ attr_reader :version_file, :key_file, :fullchain_file, :chain_file, :certificate_file
19
+ def atomic?; !!@atomic; end
20
+
21
+ def perform!
22
+ if local_version == cert.version
23
+ return
24
+ end
25
+
26
+ log "Saving certificate CN=#{cert.common_name} (ver: #{cert.version})"
27
+
28
+ write_file(key_file, key_mode, cert.private_key)
29
+ write_file(certificate_file, certificate_mode, cert.certificate.to_pem)
30
+ write_file(chain_file, certificate_mode, cert.chain)
31
+ write_file(fullchain_file, certificate_mode, cert.fullchain)
32
+ write_file(version_file, certificate_mode, cert.version)
33
+ end
34
+
35
+ def local_version
36
+ @local_version ||= begin
37
+ if version_file && File.exist?(version_file)
38
+ File.read(version_file).chomp
39
+ else
40
+ nil
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def log(*args)
48
+ if @verbose
49
+ puts *args
50
+ end
51
+ end
52
+
53
+ def write_file(path, mode, body)
54
+ return unless path
55
+ realpath = atomic? ? "#{path}.new" : path
56
+ File.open(realpath, 'w', mode.to_i(8)) do |io|
57
+ io.puts body
58
+ end
59
+ if atomic?
60
+ File.rename realpath, path
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module Acmesmith
2
- VERSION = "0.10.0"
2
+ VERSION = "0.11.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acmesmith
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sorah (Shota Fukumori)
@@ -133,6 +133,7 @@ files:
133
133
  - lib/acmesmith/post_issuing_hooks/acm.rb
134
134
  - lib/acmesmith/post_issuing_hooks/base.rb
135
135
  - lib/acmesmith/post_issuing_hooks/shell.rb
136
+ - lib/acmesmith/save_certificate_service.rb
136
137
  - lib/acmesmith/storages.rb
137
138
  - lib/acmesmith/storages/base.rb
138
139
  - lib/acmesmith/storages/filesystem.rb