Acmesmith: An effective ACME client to operate on multiple servers environment with the cloud
Acmesmith is an ACME (Automatic Certificate Management Environment) 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.
This tool is written in Ruby, but this saves certificates in simple scheme, so you can fetch certificate by your own simple scripts.
Features
- ACME client designed to work on multiple servers
- ACME registration, domain authorization, certificate requests
- Tested against Let's encrypt
- Storing keys in several ways
- Currently AWS S3 is supported
- Challenge response
- Currently
dns-01
with AWS Route 53 is supported
- Currently
Planned
- Automated deployments support (post issurance hook)
- Example shellscripts to fetch certificates
Installation
Add this line to your application's Gemfile:
gem 'acmesmith'
And then execute:
$ bundle
Or install it yourself as:
$ gem install acmesmith
Usage
$ acmesmith register CONTACT # Create account key (contact e.g. mailto:[email protected])
$ acmesmith authorize DOMAIN # Get authz for DOMAIN.
$ acmesmith request COMMON_NAME [SAN] # request certificate for CN +COMMON_NAME+ with SANs +SAN+
$ acmesmith add-san COMMON_NAME [SAN] # re-request existing certificate of CN with additional SAN(s)
$ acmesmith list [COMMON_NAME] # list certificates or its versions
$ acmesmith current COMMON_NAME # show current version for certificate
$ acmesmith show-certificate COMMON_NAME # show certificate
$ acmesmith show-private-key COMMON_NAME # show private key
$ acmesmith save-certificate COMMON_NAME --output=PATH # Save certificate to a file
$ acmesmith save-private-key COMMON_NAME --output=PATH # Save private key to a file
$ acmesmith autorenew [-d DAYS] # Renew certificates which being expired soon
See acmesmith help [subcommand]
for more help.
Configuration
See config.sample.yml to start. Default configuration file is ./acmesmith.yml
.
endpoint: https://acme-staging.api.letsencrypt.org/
# endpoint: https://acme-v01.api.letsencrypt.org/ # productilon
storage:
# configure where to store keys and certificates; described later
challenge_responders:
# configure how to respond ACME challenges; described later
account_key_passphrase: password
certificate_key_passphrase: secret
Storage
S3
storage:
type: s3
region:
bucket:
# prefix:
# aws_access_key: # aws credentials (optional); If omit, default configuration of aws-sdk use will be used.
# access_key_id:
# secret_access_key:
# session_token:
# use_kms: true
# kms_key_id: # KMS key id (optional); if omit, default AWS managed key for S3 will be used
# kms_key_id_account: # KMS key id for account key (optional); This overrides kms_key_id
# kms_key_id_certificate_key: # KMS key id for private keys for certificates (optional); This oveerides kms_key_id
This saves certificates and keys in the following S3 keys:
{prefix}/account.pem
: Account private key in pem{prefix}/certs/{common_name}/current
: text file contains current version name{prefix}/certs/{common_name}/{version}/cert.pem
: certificate in pem{prefix}/certs/{common_name}/{version}/key.pem
: private key in pem{prefix}/certs/{common_name}/{version}/chain.pem
: CA chain in pem{prefix}/certs/{common_name}/{version}/fullchain.pem
: certificate + CA chain in pem. This is suitable for some server softwares like nginx.
Filesystem
This is not recommended. If you're planning to use this, make sure backing up the keys.
storage:
type: filesystem
path: /path/to/directory/to/store/keys
Challenge Responders
Challenge responders responds to ACME challenges to prove domain ownership to CA.
Route53
Route53 responder supports dns-01
challenge type. This assumes domain NS are managed under Route53 hosted zone.
challenge_responders:
- route53:
# aws_access_key: # aws credentials (optional); If omit, default configuration of aws-sdk use will be used.
# access_key_id:
# secret_access_key:
# session_token:
# hosted_zone_map: # hosted zone map (optional); This is to specify exactly one hosted zone to use. This will be required when there are multiple hosted zone with same domain name. Usually
# "example.org.": "/hostedzone/DEADBEEF"
Vendor dependent notes
AWS
IAM policy
All access (S3 + Route53 setup)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
"Resource": ["arn:aws:s3:::{BUCKET-NAME}", "arn:aws:s3:::{BUCKET-NAME}/*"]
},
{
"Effect": "Allow",
"Action": ["route53:ListHostedZones", "route53:GetChange"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "route53:ChangeResourceRecordSets",
"Resource": ["arn:aws:route53:::hostedzone/*"]
}
]
}
Note: You can limit allowed hosted zone by modifying Resource
of route53:ChangeResourceRecordSets
Only fetching certificates
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::{BUCKET-NAME}/certs/*"]
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::{BUCKET-NAME}"],
"Condition": {
"StringEquals": {
"s3:delimiter": "/"
},
"StringLike": {
"s3:prefix": "certs/*",
}
}
}
]
}
AWS KMS key policy for customer managed keys
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:
Be sure to replace {S3-REGION}
and {YOUR-AWS-ACCOUNT-ID}
before applying it.
{
"Version": "2012-10-17",
"Id": "kms-acmesmith-s3-policy",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "s3.{S3-REGION}.amazonaws.com",
"kms:CallerAccount": "{YOUR-AWS-ACCOUNT-ID}"
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{YOUR-AWS-ACCOUNT-ID}:root"
},
"Action": [
"kms:Describe*",
"kms:Get*",
"kms:List*",
"kms:Put*"
],
"Resource": "*"
}
]
}
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Todos
- Tests
- Support post actions (notifying servers, deploying to somewhere, etc...)
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/acmesmith.
License
The gem is available as open source under the terms of the MIT License.