acmesmith 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -107
- data/docs/vendor/aws.md +106 -0
- data/lib/acmesmith/command.rb +38 -10
- data/lib/acmesmith/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4eabbcb2bb88783d1b487344b1022f921968f2f
|
4
|
+
data.tar.gz: 2a664ea8940194eb01f951ebdddc3dd3cf81ec65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95858bf33cf374a349ec1ee5c45c5be68ee914294801a603151fcbe76b943a7c59918795cbfbee99b09597058c4b648240d6e66eec6ab8e0648c232eff66d054
|
7
|
+
data.tar.gz: dba846aad843896b668640663b0c67e15f5de36a706dbada70dfab566ef5883821828803f3bfc6bcc79f9440366ce20dad760ff2ebfa6e15d8f2b57007c489a9
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Acmesmith:
|
1
|
+
# Acmesmith: A simple, effective ACME client to use with many servers and a cloud
|
2
2
|
|
3
3
|
Acmesmith is an [ACME (Automatic Certificate Management Environment)](https://github.com/ietf-wg-acme/acme) client that works perfect on environment with multiple servers. This client saves certificate and keys on cloud services (e.g. AWS S3) securely, then allow to deploy issued certificates onto your servers smoothly. This works well on [Let's encrypt](https://letsencrypt.org).
|
4
4
|
|
5
|
-
This tool is written in Ruby, but
|
5
|
+
This tool is written in Ruby, but Acmesmith saves certificates in simple scheme, so you can fetch certificate by your own simple scripts.
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
@@ -13,6 +13,9 @@ This tool is written in Ruby, but this saves certificates in simple scheme, so y
|
|
13
13
|
- Currently AWS S3 is supported
|
14
14
|
- Challenge response
|
15
15
|
- Currently `dns-01` with AWS Route 53 is supported
|
16
|
+
- Pluggable modules, you can use 3rd party one or write:
|
17
|
+
- Storages for other than AWS S3
|
18
|
+
- Challenge reponses for other than AWS Route53 or dns-01 challenges, like for Openstack DNSaaS.
|
16
19
|
|
17
20
|
### Planned
|
18
21
|
|
@@ -54,6 +57,7 @@ $ acmesmith show-certificate COMMON_NAME # show certificate
|
|
54
57
|
$ acmesmith show-private-key COMMON_NAME # show private key
|
55
58
|
$ acmesmith save-certificate COMMON_NAME --output=PATH # Save certificate to a file
|
56
59
|
$ acmesmith save-private-key COMMON_NAME --output=PATH # Save private key to a file
|
60
|
+
$ acmesmith save-pkcs12 COMMON_NAME --output=PATH # Save certificate and private key to a PKCS12 file
|
57
61
|
```
|
58
62
|
|
59
63
|
```
|
@@ -137,114 +141,15 @@ challenge_responders:
|
|
137
141
|
# "example.org.": "/hostedzone/DEADBEEF"
|
138
142
|
```
|
139
143
|
|
140
|
-
##
|
144
|
+
## 3rd party Plugins
|
141
145
|
|
142
|
-
###
|
143
|
-
|
144
|
-
#### IAM policy
|
145
|
-
|
146
|
-
##### All access (S3 + Route53 setup)
|
147
|
-
|
148
|
-
``` json
|
149
|
-
{
|
150
|
-
"Version": "2012-10-17",
|
151
|
-
"Statement": [
|
152
|
-
{
|
153
|
-
"Effect": "Allow",
|
154
|
-
"Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
|
155
|
-
"Resource": ["arn:aws:s3:::{BUCKET-NAME}", "arn:aws:s3:::{BUCKET-NAME}/*"]
|
156
|
-
},
|
157
|
-
{
|
158
|
-
"Effect": "Allow",
|
159
|
-
"Action": ["route53:ListHostedZones", "route53:GetChange"],
|
160
|
-
"Resource": "*"
|
161
|
-
},
|
162
|
-
{
|
163
|
-
"Effect": "Allow",
|
164
|
-
"Action": "route53:ChangeResourceRecordSets",
|
165
|
-
"Resource": ["arn:aws:route53:::hostedzone/*"]
|
166
|
-
}
|
167
|
-
]
|
168
|
-
}
|
169
|
-
```
|
146
|
+
### Challenge responders
|
170
147
|
|
171
|
-
|
172
|
-
|
173
|
-
##### Only fetching certificates
|
174
|
-
|
175
|
-
``` json
|
176
|
-
{
|
177
|
-
"Version": "2012-10-17",
|
178
|
-
"Statement": [
|
179
|
-
{
|
180
|
-
"Effect": "Allow",
|
181
|
-
"Action": ["s3:GetObject"],
|
182
|
-
"Resource": ["arn:aws:s3:::{BUCKET-NAME}/certs/*"]
|
183
|
-
},
|
184
|
-
{
|
185
|
-
"Effect": "Allow",
|
186
|
-
"Action": ["s3:ListBucket"],
|
187
|
-
"Resource": ["arn:aws:s3:::{BUCKET-NAME}"],
|
188
|
-
"Condition": {
|
189
|
-
"StringEquals": {
|
190
|
-
"s3:delimiter": "/"
|
191
|
-
},
|
192
|
-
"StringLike": {
|
193
|
-
"s3:prefix": "certs/*",
|
194
|
-
}
|
195
|
-
}
|
196
|
-
}
|
197
|
-
]
|
198
|
-
}
|
199
|
-
```
|
148
|
+
- [hanazuki/acmesmith-designate](https://github.com/hanazuki/acmesmith-designate) `dns-01` challenge responder with OpenStack-based DNSaaS (Designate v1 API), e.g. for ConoHa.
|
200
149
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
Be sure to replace `{S3-REGION}` and `{YOUR-AWS-ACCOUNT-ID}` before applying it.
|
206
|
-
|
207
|
-
``` json
|
208
|
-
{
|
209
|
-
"Version": "2012-10-17",
|
210
|
-
"Id": "kms-acmesmith-s3-policy",
|
211
|
-
"Statement": [
|
212
|
-
{
|
213
|
-
"Effect": "Allow",
|
214
|
-
"Principal": {
|
215
|
-
"AWS": "*"
|
216
|
-
},
|
217
|
-
"Action": [
|
218
|
-
"kms:Encrypt",
|
219
|
-
"kms:Decrypt",
|
220
|
-
"kms:ReEncrypt*",
|
221
|
-
"kms:GenerateDataKey*",
|
222
|
-
"kms:DescribeKey"
|
223
|
-
],
|
224
|
-
"Resource": "*",
|
225
|
-
"Condition": {
|
226
|
-
"StringEquals": {
|
227
|
-
"kms:ViaService": "s3.{S3-REGION}.amazonaws.com",
|
228
|
-
"kms:CallerAccount": "{YOUR-AWS-ACCOUNT-ID}"
|
229
|
-
}
|
230
|
-
}
|
231
|
-
},
|
232
|
-
{
|
233
|
-
"Effect": "Allow",
|
234
|
-
"Principal": {
|
235
|
-
"AWS": "arn:aws:iam::{YOUR-AWS-ACCOUNT-ID}:root"
|
236
|
-
},
|
237
|
-
"Action": [
|
238
|
-
"kms:Describe*",
|
239
|
-
"kms:Get*",
|
240
|
-
"kms:List*",
|
241
|
-
"kms:Put*"
|
242
|
-
],
|
243
|
-
"Resource": "*"
|
244
|
-
}
|
245
|
-
]
|
246
|
-
}
|
247
|
-
```
|
150
|
+
## Vendor dependent notes
|
151
|
+
|
152
|
+
- [./docs/vendor/aws.md](./docs/vendor/aws.md): IAM and KMS key policies, and some tips
|
248
153
|
|
249
154
|
## Development
|
250
155
|
|
data/docs/vendor/aws.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
#### IAM policy
|
2
|
+
|
3
|
+
##### All access (S3 + Route53 setup)
|
4
|
+
|
5
|
+
``` json
|
6
|
+
{
|
7
|
+
"Version": "2012-10-17",
|
8
|
+
"Statement": [
|
9
|
+
{
|
10
|
+
"Effect": "Allow",
|
11
|
+
"Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
|
12
|
+
"Resource": ["arn:aws:s3:::{BUCKET-NAME}", "arn:aws:s3:::{BUCKET-NAME}/*"]
|
13
|
+
},
|
14
|
+
{
|
15
|
+
"Effect": "Allow",
|
16
|
+
"Action": ["route53:ListHostedZones", "route53:GetChange"],
|
17
|
+
"Resource": "*"
|
18
|
+
},
|
19
|
+
{
|
20
|
+
"Effect": "Allow",
|
21
|
+
"Action": "route53:ChangeResourceRecordSets",
|
22
|
+
"Resource": ["arn:aws:route53:::hostedzone/*"]
|
23
|
+
}
|
24
|
+
]
|
25
|
+
}
|
26
|
+
```
|
27
|
+
|
28
|
+
Note: You can limit allowed hosted zone by modifying `Resource` of `route53:ChangeResourceRecordSets`
|
29
|
+
|
30
|
+
##### Only fetching certificates
|
31
|
+
|
32
|
+
``` json
|
33
|
+
{
|
34
|
+
"Version": "2012-10-17",
|
35
|
+
"Statement": [
|
36
|
+
{
|
37
|
+
"Effect": "Allow",
|
38
|
+
"Action": ["s3:GetObject"],
|
39
|
+
"Resource": ["arn:aws:s3:::{BUCKET-NAME}/certs/*"]
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"Effect": "Allow",
|
43
|
+
"Action": ["s3:ListBucket"],
|
44
|
+
"Resource": ["arn:aws:s3:::{BUCKET-NAME}"],
|
45
|
+
"Condition": {
|
46
|
+
"StringEquals": {
|
47
|
+
"s3:delimiter": "/"
|
48
|
+
},
|
49
|
+
"StringLike": {
|
50
|
+
"s3:prefix": "certs/*"
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
]
|
55
|
+
}
|
56
|
+
```
|
57
|
+
|
58
|
+
#### AWS KMS key policy for customer managed keys
|
59
|
+
|
60
|
+
If you're going to use `aws_kms_id` option to use customer managed keys instead of AWS managed default KMS key for Amazon S3, use the following policy as base:
|
61
|
+
|
62
|
+
Be sure to replace `{S3-REGION}` and `{YOUR-AWS-ACCOUNT-ID}` before applying it.
|
63
|
+
|
64
|
+
``` json
|
65
|
+
{
|
66
|
+
"Version": "2012-10-17",
|
67
|
+
"Id": "kms-acmesmith-s3-policy",
|
68
|
+
"Statement": [
|
69
|
+
{
|
70
|
+
"Effect": "Allow",
|
71
|
+
"Principal": {
|
72
|
+
"AWS": "*"
|
73
|
+
},
|
74
|
+
"Action": [
|
75
|
+
"kms:Encrypt",
|
76
|
+
"kms:Decrypt",
|
77
|
+
"kms:ReEncrypt*",
|
78
|
+
"kms:GenerateDataKey*",
|
79
|
+
"kms:DescribeKey"
|
80
|
+
],
|
81
|
+
"Resource": "*",
|
82
|
+
"Condition": {
|
83
|
+
"StringEquals": {
|
84
|
+
"kms:ViaService": "s3.{S3-REGION}.amazonaws.com",
|
85
|
+
"kms:CallerAccount": "{YOUR-AWS-ACCOUNT-ID}"
|
86
|
+
}
|
87
|
+
}
|
88
|
+
},
|
89
|
+
{
|
90
|
+
"Effect": "Allow",
|
91
|
+
"Principal": {
|
92
|
+
"AWS": "arn:aws:iam::{YOUR-AWS-ACCOUNT-ID}:root"
|
93
|
+
},
|
94
|
+
"Action": [
|
95
|
+
"kms:Describe*",
|
96
|
+
"kms:Get*",
|
97
|
+
"kms:List*",
|
98
|
+
"kms:Put*"
|
99
|
+
],
|
100
|
+
"Resource": "*"
|
101
|
+
}
|
102
|
+
]
|
103
|
+
}
|
104
|
+
```
|
105
|
+
|
106
|
+
|
data/lib/acmesmith/command.rb
CHANGED
@@ -34,17 +34,23 @@ module Acmesmith
|
|
34
34
|
|
35
35
|
responder.respond(domain, challenge)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
begin
|
38
|
+
puts "=> Requesting verification..."
|
39
|
+
challenge.request_verification
|
40
|
+
loop do
|
41
|
+
status = challenge.verify_status
|
42
|
+
puts " * verify_status: #{status}"
|
43
|
+
break if status == 'valid'
|
44
|
+
if status == "invalid"
|
45
|
+
err = challenge.error
|
46
|
+
puts "#{err["type"]}: #{err["detail"]}"
|
47
|
+
end
|
48
|
+
sleep 3
|
49
|
+
end
|
50
|
+
puts "=> Done"
|
51
|
+
ensure
|
52
|
+
responder.cleanup(domain, challenge)
|
44
53
|
end
|
45
|
-
|
46
|
-
responder.cleanup(domain, challenge)
|
47
|
-
puts "=> Done"
|
48
54
|
end
|
49
55
|
|
50
56
|
desc "request COMMON_NAME [SAN]", "request certificate for CN +COMMON_NAME+ with SANs +SAN+"
|
@@ -126,6 +132,28 @@ module Acmesmith
|
|
126
132
|
end
|
127
133
|
end
|
128
134
|
|
135
|
+
desc 'save-pkcs12 COMMON_NAME', 'Save ceriticate and private key to .p12 file'
|
136
|
+
method_option :version, type: :string, default: 'current'
|
137
|
+
method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
|
138
|
+
method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
|
139
|
+
def save_pkcs12(common_name)
|
140
|
+
cert = storage.get_certificate(common_name, version: options[:version])
|
141
|
+
cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
|
142
|
+
|
143
|
+
print 'Passphrase: '
|
144
|
+
passphrase = $stdin.noecho { $stdin.gets }.chomp
|
145
|
+
print "\nPassphrase (confirm): "
|
146
|
+
passphrase2 = $stdin.noecho { $stdin.gets }.chomp
|
147
|
+
puts
|
148
|
+
|
149
|
+
raise ArgumentError, "Passphrase doesn't match" if passphrase != passphrase2
|
150
|
+
|
151
|
+
p12 = OpenSSL::PKCS12.create(passphrase, cert.common_name, cert.private_key, cert.certificate)
|
152
|
+
File.open(options[:output], 'w', options[:mode].to_i(8)) do |f|
|
153
|
+
f.puts p12.to_der
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
129
157
|
desc "autorenew", "request renewal of certificates which expires soon"
|
130
158
|
method_option :days, aliases: %w(-d), default: 7, desc: 'specify threshold in days to select certificates to renew'
|
131
159
|
def autorenew
|
data/lib/acmesmith/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acmesmith
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sorah (Shota Fukumori)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acme-client
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- acmesmith.gemspec
|
118
118
|
- bin/acmesmith
|
119
119
|
- config.sample.yml
|
120
|
+
- docs/vendor/aws.md
|
120
121
|
- lib/acmesmith.rb
|
121
122
|
- lib/acmesmith/account_key.rb
|
122
123
|
- lib/acmesmith/certificate.rb
|
@@ -153,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
154
|
version: '0'
|
154
155
|
requirements: []
|
155
156
|
rubyforge_project:
|
156
|
-
rubygems_version: 2.
|
157
|
+
rubygems_version: 2.6.4
|
157
158
|
signing_key:
|
158
159
|
specification_version: 4
|
159
160
|
summary: ACME client (Let's encrypt client) to manage certificate in multi server
|