This module can be used to generate a Certificate Authority (CA) public key and the public and private keys of a
TLS certificate signed by this CA. This certificate is meant to be used with private services, such as a Vault
cluster accessed solely within your AWS account. For publicly-accessible services, especially services you access
through a web browser, you should NOT use this module, and instead get certificates from a commercial Certificate
Authority, such as Let's Encrypt.
If you're unfamiliar with how TLS certificates work, check out the Background section.
Quick start
Copy this module to your computer.
Open variables.tf and fill in the variables that do not have a default.
DO NOT configure Terraform remote state storage for this code. You do NOT want to store the state files as they
will contain the private keys for the certificates.
Run terraform apply. The output will show you the paths to the generated files:
The Terraform state will contain the private keys for the certificates, so it's important to clean it up!
To inspect a certificate, you can use OpenSSL:
opensslx509-informpem-noout-text-invault.crt.pem
Now that you have your TLS certs, check out the next section for how to use them.
Using TLS certs
Distributing TLS certs to your servers
Distribute the private and public keys (the files at private_key_file_path and public_key_file_path) to the
servers that will use them to handle TLS connections (e.g. Vault). For example, to run Vault with the run-vault
module, you need to pass it the TLS certs:
We strongly recommend encrypting the private key file while it's in transit to the servers that will use it. Here
are some of the ways you could do this:
Encrypt the certificate using KMS and include the encrypted files in the AMI for your
Vault servers. Give those servers an IAM role that lets them access the same KMS key and decrypt their certs just
before booting.
Put your TLS cert in a secure S3 Bucket with encryption enabled. Give your Vault servers an IAM role that allows them
to download the certs from the S3 bucket just before booting.
Manually upload the certificate to each EC2 Instance with scp.
Distributing TLS certs to your clients
Distribute the CA public key (the file at ca_public_key_file_path) to any clients of those services so they can
validate the server's TLS cert. Without the CA public key, the clients will reject any TLS connections:
vault read secret/foo
Error initializing Vault: Get https://127.0.0.1:8200/v1/secret/foo: x509: certificate signed by unknown authority
Most TLS clients offer a way to explicitly specify extra public keys that you want to trust. For example, with
Vault, you do this via the -ca-cert argument:
vault read -ca-cert=ca.crt.pem secret/foo
Key Value--- -----
refresh_interval 768h0m0s
value bar
As an alternative, you can configure the certificate trust on your server so that all TLS clients trust your CA
public key by running the update-certificate-store module on your server. Once
you do that, your system will trust the public key without having to pass it in explicitly:
update-certificate-store--cert-file /opt/vault/tls/ca.crt.pem
vault read secret/foo
KeyValue--- -----
refresh_interval 768h0m0s
value bar
Background
How TLS/SSL Works
The industry-standard way to add encryption for data in motion is to use TLS (the successor to SSL). There are many
examples online explaining how TLS works, but here are the basics:
Some entity decides to be a "Certificate Authority" ("CA") meaning it will issue TLS certificates to websites or
other services
An entity becomes a Certificate Authority by creating a public/private key pair and publishing the public portion
(typically known as the "CA Cert"). The private key is kept under the tightest possible security since anyone who
possesses it could issue TLS certificates as if they were this Certificate Authority!
In fact, the consequences of a CA's private key being compromised are so disastrous that CA's typically create an
"intermediate" CA keypair with their "root" CA key, and only issue TLS certificates with the intermediate key.
Your client (e.g. a web browser) can decide to trust this newly created Certificate Authority by including its CA
Cert (the CA's public key) when making an outbound request to a service that uses the TLS certificate.
When CAs issue a TLS certificate ("TLS cert") to a service, they again create a public/private keypair, but this time
the public key is "signed" by the CA. That public key is what you view when you click on the lock icon in a web
browser and what a service "advertises" to any clients such as web browsers to declare who it is. When we say that
the CA signed a public key, we mean that, cryptographically, any possessor of the CA Cert can validate that this same
CA issued this particular public key.
The public key is more generally known as the TLS cert.
The private key created by the CA must be kept secret by the service since the possessor of the private key can
"prove" they are whoever the TLS cert (public key) claims to be as part of the TLS protocol.
How does that "proof" work? Well, your web browser will attempt to validate the TLS cert in two ways:
First, it will ensure this public key (TLS cert) is in fact signed by a CA it trusts.
Second, using the TLS protocol, your browser will encrypt a message with the public key (TLS cert) that only the
possessor of the corresponding private key can decrypt. In this manner, your browser will be able to come up with a
symmetric encryption key it can use to encrypt all traffic for just that one web session.
Now your client/browser has:
declared which CA it will trust
verified that the service it's connecting to possesses a certificate issued by a CA it trusts
used that service's public key (TLS cert) to establish a secure session
Commercial or Public Certificate Authorities
For public services like banks, healthcare, and the like, it makes sense to use a "Commercial CA" like Verisign, Thawte,
or Digicert, or better yet a widely trusted but free service like Let's Encrypt. That's
because every web browser comes pre-configured with a set of CA's that it trusts. This means the client connecting to
the bank doesn't have to know anything about CA's at all. Instead, their web browser is configured to trust the CA that
happened to issue the bank's certificate.
Connecting securely to private services is similar to connecting to your bank's website over TLS, with one primary
difference: We want total control over the CA.
Imagine if we used a commercial CA to issue our private TLS certificate and that commercial or public CA--which we
don't control--were compromised. Now the attackers of that commercial or public CA could impersonate our private server.
And indeed, ithashappened
multiple times.
How We'll Generate a TLS Cert for Private Services
One option is to be very selective about choosing a commercial CA, but to what benefit? What we want instead is
assurance that our private service really was launched by people we trust. Those same people--let's call them our
"operators"--can become their own CA and generate their own TLS certificate for the private service.
Sure, no one else in the world will trust this CA, but we don't care because we only need our organization to trust
this CA.
So here's our strategy for issuing a TLS Cert for a private service:
Create our own CA.
If a client wishes to trust our CA, they need only reference this CA public key.
We'll deal with the private key in a moment.
Using our CA, issue a TLS Certificate for our private service.
Create a public/private key pair for the private service, and have the CA sign the public key.
This means anyone who trusts the CA will trust that the possessor of the private key that corresponds to this public
key is who they claim to be.
We will be extremely careful with the TLS private key since anyone who obtains it can impersonate our private
service! For this reason, we recommend immediately encrypting the private key with
KMS.
Freely advertise our CA's public key to all internal services.
Any service that wishes to connect securely to our private service will need our CA's public key so it can declare
that it trusts this CA, and thereby the TLS cert it issued to the private service.
Throw away the CA private key.
By erasing a CA private key it's impossible for the CA to be compromised, because there's no private key to steal!
Future certs can be generated with a new CA.
Questions? Ask away.
We're here to talk about our services, answer any questions, give advice, or just to chat.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"0bb5646ebd82744f75208b42efc63cfd43474852"}]},{"name":".gitignore","path":".gitignore","sha":"6c4ebe4426586b7febbaba178294ef59b8272c05"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"4be01a6334d39aa5bf6abe6baae701f5e2a8c5ac"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","sha":"ea1ca5c8d6ff2d0d62880ee0ea80ef86e0b87dad"},{"name":"LICENSE","path":"LICENSE","sha":"7a4a3ea2424c09fbe48d455aed1eaa94d9124835"},{"name":"NOTICE","path":"NOTICE","sha":"2288082e33ae18a610f6a7747180f7e05e47a001"},{"name":"README.md","path":"README.md","sha":"1a2de50f26400eda43c1067fccf4aa49b3db8dfe"},{"name":"_ci","children":[{"name":"publish-amis-in-new-account.md","path":"_ci/publish-amis-in-new-account.md","sha":"3182a0a90775f7bb9622c037196ac2a1f15e455d"},{"name":"publish-amis.sh","path":"_ci/publish-amis.sh","sha":"3d4a46a02f26d45a5fc27cce07cd3db7bc140399"}]},{"name":"_docs","children":[{"name":"amazon-linux-ami-list.md","path":"_docs/amazon-linux-ami-list.md","sha":"be9f50c689839b099d0222711ec13a86108660f0"},{"name":"architecture-elb.png","path":"_docs/architecture-elb.png","sha":"9e02e4f53afdd2929ec4fc4246ae5e47bd49f295"},{"name":"architecture-with-s3.png","path":"_docs/architecture-with-s3.png","sha":"8a91ef2d06665e40fe82a8ccf7ae4281f338fd50"},{"name":"architecture.png","path":"_docs/architecture.png","sha":"a9f6098b37b1aaafe8c744b154208efc3e642881"},{"name":"ubuntu16-ami-list.md","path":"_docs/ubuntu16-ami-list.md","sha":"60caafe1f2b90046e819f373ed22c0df47043f03"}]},{"name":"examples","children":[{"name":"root-example","children":[{"name":"README.md","path":"examples/root-example/README.md","sha":"4d73916c181c9c4157905162d4ed66d2d7427342"},{"name":"user-data-consul.sh","path":"examples/root-example/user-data-consul.sh","sha":"5043e6904cab4564ed0c7f8337599a884f96a194"},{"name":"user-data-vault.sh","path":"examples/root-example/user-data-vault.sh","sha":"26fad57bb49a78e4e2a4b7ce52427efb27e87ced"}]},{"name":"vault-agent","children":[{"name":"README.md","path":"examples/vault-agent/README.md","sha":"0a80c92a455171b6af0e1774a1e67adee32579d6"},{"name":"main.tf","path":"examples/vault-agent/main.tf","sha":"1411aff0b44e6554a96d0481d0ffa31a1b4a27ea"},{"name":"outputs.tf","path":"examples/vault-agent/outputs.tf","sha":"16bb9676e7fa2ec2bb5148c5ca5763d7c01db837"},{"name":"user-data-auth-client.sh","path":"examples/vault-agent/user-data-auth-client.sh","sha":"9ff5ebc6c45f791f9357a71a7f3415f1e333b61e"},{"name":"user-data-consul.sh","path":"examples/vault-agent/user-data-consul.sh","sha":"0c96497e38b05e5b5a54277c95ae129827a3daa2"},{"name":"user-data-vault.sh","path":"examples/vault-agent/user-data-vault.sh","sha":"49983b4b543bd7d28c2adde81629d4a3867ffe13"},{"name":"variables.tf","path":"examples/vault-agent/variables.tf","sha":"9abf58af8a0dc24bd445a1b779f07fcf48a05a0e"}]},{"name":"vault-auto-unseal","children":[{"name":"README.md","path":"examples/vault-auto-unseal/README.md","sha":"770b559d99f84ce103f01fddcdc10c1fef58d482"},{"name":"main.tf","path":"examples/vault-auto-unseal/main.tf","sha":"56169fcd17ecacb9dd028c7f9e8a1e880a9badd6"},{"name":"outputs.tf","path":"examples/vault-auto-unseal/outputs.tf","sha":"9e7ebd3be30c61662e8647cfecfec210de53e6d2"},{"name":"user-data-consul.sh","path":"examples/vault-auto-unseal/user-data-consul.sh","sha":"0c96497e38b05e5b5a54277c95ae129827a3daa2"},{"name":"user-data-vault.sh","path":"examples/vault-auto-unseal/user-data-vault.sh","sha":"1d9533ea3ba6f9b89242ce503e8b7ea1e59579ba"},{"name":"variables.tf","path":"examples/vault-auto-unseal/variables.tf","sha":"03847da844d2c5a5c24a27872324da11249d11de"}]},{"name":"vault-cluster-private","children":[{"name":"README.md","path":"examples/vault-cluster-private/README.md","sha":"9467091dc2b6475148cecf2d9c84ed387d78d4a8"},{"name":"main.tf","path":"examples/vault-cluster-private/main.tf","sha":"8d799c376e723c81a781fee11a5ca279fc6aeac4"},{"name":"outputs.tf","path":"examples/vault-cluster-private/outputs.tf","sha":"9e7ebd3be30c61662e8647cfecfec210de53e6d2"},{"name":"user-data-consul.sh","path":"examples/vault-cluster-private/user-data-consul.sh","sha":"5043e6904cab4564ed0c7f8337599a884f96a194"},{"name":"user-data-vault.sh","path":"examples/vault-cluster-private/user-data-vault.sh","sha":"ef32d804ab9f1807730bae1551fc3fd3fff6da95"},{"name":"variables.tf","path":"examples/vault-cluster-private/variables.tf","sha":"3e919aff20454c6ef004986d3f28b7f65c5d9379"}]},{"name":"vault-consul-ami","children":[{"name":"README.md","path":"examples/vault-consul-ami/README.md","sha":"97b6eeaf3f45cb12b227eb47059042630ec342a4"},{"name":"auth","children":[{"name":"sign-request.py","path":"examples/vault-consul-ami/auth/sign-request.py","sha":"cba97708676a0d3aa8068ee1b5ecb3bf8d14067f"}]},{"name":"tls","children":[{"name":"README.md","path":"examples/vault-consul-ami/tls/README.md","sha":"92f88219562304b995bd78889a24047bdde336af"},{"name":"ca.crt.pem","path":"examples/vault-consul-ami/tls/ca.crt.pem","sha":"9bf1a62b0649d1ab5c0b16710166c146a1fd1fa3"},{"name":"vault.crt.pem","path":"examples/vault-consul-ami/tls/vault.crt.pem","sha":"e642f0b108bfdebe56331111ce9ce75f8ff42f52"},{"name":"vault.key.pem","path":"examples/vault-consul-ami/tls/vault.key.pem","sha":"0103aa55a5a68ffc002c7c9c14a292adbd97fd2d"}]},{"name":"vault-consul.json","path":"examples/vault-consul-ami/vault-consul.json","sha":"4ca1f5c3c396ab201c5521c6d9efd18fa02faca8"}]},{"name":"vault-dynamodb-backend","children":[{"name":"README.md","path":"examples/vault-dynamodb-backend/README.md","sha":"2249ed2b41e02d06f44df46da19bb344c2f3f912"},{"name":"dynamodb","children":[{"name":"main.tf","path":"examples/vault-dynamodb-backend/dynamodb/main.tf","sha":"7405fba8bd36bc376fe09282d1b2741411c5ed5f"},{"name":"variables.tf","path":"examples/vault-dynamodb-backend/dynamodb/variables.tf","sha":"c48d524ca416c19f4d96a7b860342c07252a8587"}]},{"name":"main.tf","path":"examples/vault-dynamodb-backend/main.tf","sha":"1452cad776f0355c73496d9cbb5cbc79d3bcbf6a"},{"name":"outputs.tf","path":"examples/vault-dynamodb-backend/outputs.tf","sha":"f57334a298c9a9f4eb0c3aaae70619cda73ccbb9"},{"name":"user-data-vault.sh","path":"examples/vault-dynamodb-backend/user-data-vault.sh","sha":"6ff712c8839ce577cb8229df9a6e17685da2820f"},{"name":"variables.tf","path":"examples/vault-dynamodb-backend/variables.tf","sha":"928f9b9e96dda6aa85429d27ab6badb87bfd5314"}]},{"name":"vault-ec2-auth","children":[{"name":"README.md","path":"examples/vault-ec2-auth/README.md","sha":"29af1121fa99b3903b09447c79e127daecb30bfb"},{"name":"images","children":[{"name":"ec2-auth.png","path":"examples/vault-ec2-auth/images/ec2-auth.png","sha":"a98fb916ed6a32204efbc525cac59c0d570d619d"}]},{"name":"main.tf","path":"examples/vault-ec2-auth/main.tf","sha":"5417c9d851c4b9ad99033205e615aff8c9b59cf1"},{"name":"outputs.tf","path":"examples/vault-ec2-auth/outputs.tf","sha":"8694fbce70e13690b8bca4bab50d2570dcd7bdd9"},{"name":"user-data-auth-client.sh","path":"examples/vault-ec2-auth/user-data-auth-client.sh","sha":"e049ec6dca2d35d6fde5badec4e48ecafe8bfc38"},{"name":"user-data-consul.sh","path":"examples/vault-ec2-auth/user-data-consul.sh","sha":"0c96497e38b05e5b5a54277c95ae129827a3daa2"},{"name":"user-data-vault.sh","path":"examples/vault-ec2-auth/user-data-vault.sh","sha":"dd8a73e43e9a4c42e4687ad4cc3c84a543ce548a"},{"name":"variables.tf","path":"examples/vault-ec2-auth/variables.tf","sha":"f04b84eac1668fa2ca3b92d50b27ca6139fde834"}]},{"name":"vault-examples-helper","children":[{"name":"README.md","path":"examples/vault-examples-helper/README.md","sha":"a28a95258bee372025e4282daf60a20d1bf96bdb"},{"name":"vault-examples-helper.sh","path":"examples/vault-examples-helper/vault-examples-helper.sh","sha":"ebe3d8b9bb599384add9a7c635b397529b10fde5"}]},{"name":"vault-iam-auth","children":[{"name":"README.md","path":"examples/vault-iam-auth/README.md","sha":"7557e5abb41341b82464a36eebd0e759d857625d"},{"name":"images","children":[{"name":"iam-auth.png","path":"examples/vault-iam-auth/images/iam-auth.png","sha":"095dcd0060f6cd1f5dad3be9d5ec83dcbba8316f"}]},{"name":"main.tf","path":"examples/vault-iam-auth/main.tf","sha":"6e1034d29495a9b8895e79f5cf716689782a51cc"},{"name":"outputs.tf","path":"examples/vault-iam-auth/outputs.tf","sha":"16bb9676e7fa2ec2bb5148c5ca5763d7c01db837"},{"name":"user-data-auth-client.sh","path":"examples/vault-iam-auth/user-data-auth-client.sh","sha":"4122511229818b6ddf8fe03fd2c314f8a1521ee2"},{"name":"user-data-consul.sh","path":"examples/vault-iam-auth/user-data-consul.sh","sha":"0c96497e38b05e5b5a54277c95ae129827a3daa2"},{"name":"user-data-vault.sh","path":"examples/vault-iam-auth/user-data-vault.sh","sha":"1f32c36dc968467fc59b44f624638e1437703fb9"},{"name":"variables.tf","path":"examples/vault-iam-auth/variables.tf","sha":"9abf58af8a0dc24bd445a1b779f07fcf48a05a0e"}]},{"name":"vault-s3-backend","children":[{"name":"README.md","path":"examples/vault-s3-backend/README.md","sha":"e37fbaec6982c87a87a16d3499db3c17f85dbbfd"},{"name":"main.tf","path":"examples/vault-s3-backend/main.tf","sha":"64617b4235bca44d381e7007a29d39a02e0edd03"},{"name":"outputs.tf","path":"examples/vault-s3-backend/outputs.tf","sha":"e1af7046390871d4e63797089c39aebab5d9ac26"},{"name":"user-data-consul.sh","path":"examples/vault-s3-backend/user-data-consul.sh","sha":"5043e6904cab4564ed0c7f8337599a884f96a194"},{"name":"user-data-vault.sh","path":"examples/vault-s3-backend/user-data-vault.sh","sha":"cfc21ee0525b0cee2753e1823b8656bf504a910a"},{"name":"variables.tf","path":"examples/vault-s3-backend/variables.tf","sha":"f526eaaa0c65aa5f8be3d4dbde0dd453781d4461"}]}]},{"name":"main.tf","path":"main.tf","sha":"3e2db19f150bfb9ae8b8d1b33ce9e20d3b076dde"},{"name":"modules","children":[{"name":"install-vault","children":[{"name":"README.md","path":"modules/install-vault/README.md","sha":"6bb7538adb7dd8f8527690d96fc06d701cd79462"},{"name":"install-vault","path":"modules/install-vault/install-vault","sha":"e1564049029f50af3507fb2e57dc188c607cb1aa"}]},{"name":"private-tls-cert","children":[{"name":"README.md","path":"modules/private-tls-cert/README.md","sha":"42f2d131477fae97cdfaeef893b3c916f2f7f209","toggled":true},{"name":"main.tf","path":"modules/private-tls-cert/main.tf","sha":"f906b61efe2b5356bcf759dc60c47a89cf853894"},{"name":"outputs.tf","path":"modules/private-tls-cert/outputs.tf","sha":"078afd869917866e91d2beab7f91fa0d14af524e"},{"name":"variables.tf","path":"modules/private-tls-cert/variables.tf","sha":"57720d8462ddd0a472082d76f1605ea32c443612"}],"toggled":true},{"name":"run-vault","children":[{"name":"README.md","path":"modules/run-vault/README.md","sha":"b2f1e1e074ffd65b4c715675bd59657c6eac6992"},{"name":"run-vault","path":"modules/run-vault/run-vault","sha":"c7982409275a9e0da41379a8eb725cbda9f932d7"}]},{"name":"update-certificate-store","children":[{"name":"README.md","path":"modules/update-certificate-store/README.md","sha":"1348a7aba71475b5a17d31f3f8d66663f656e672"},{"name":"update-certificate-store","path":"modules/update-certificate-store/update-certificate-store","sha":"e07d9a1d997843d62033ee019121895c91e29447"}]},{"name":"vault-cluster","children":[{"name":"README.md","path":"modules/vault-cluster/README.md","sha":"7b4c4ee5f59dc3a216154c4402acd70b96d6585f"},{"name":"main.tf","path":"modules/vault-cluster/main.tf","sha":"6838267cceea00aef7446fd41e6aef5c6b123c61"},{"name":"outputs.tf","path":"modules/vault-cluster/outputs.tf","sha":"ab03f0accf81c6722c79656844acd1fd39b41e87"},{"name":"variables.tf","path":"modules/vault-cluster/variables.tf","sha":"1349a6c59de0d996ac0e39c1f56d0b611bda3bec"}]},{"name":"vault-elb","children":[{"name":"README.md","path":"modules/vault-elb/README.md","sha":"9dc6564baaaaa8176f650e3c548b8c8066631b6f"},{"name":"main.tf","path":"modules/vault-elb/main.tf","sha":"0f85aea4f41332461dadcda41e767f983d53ad66"},{"name":"outputs.tf","path":"modules/vault-elb/outputs.tf","sha":"024b1c73b457ed1c9256b39fc3ee283b39ed6544"},{"name":"variables.tf","path":"modules/vault-elb/variables.tf","sha":"f6ec2cedeb90b046d4caf020482f0169f872f17d"}]},{"name":"vault-security-group-rules","children":[{"name":"README.md","path":"modules/vault-security-group-rules/README.md","sha":"48df12587b14b7a0d93333b6c12c19dc7082d8b0"},{"name":"main.tf","path":"modules/vault-security-group-rules/main.tf","sha":"c42c6e6d296dd17c021b134bb2f4c5774cf0079c"},{"name":"variables.tf","path":"modules/vault-security-group-rules/variables.tf","sha":"2e18f3fef1b2ff2b3a32f62a49085480ed61763e"}]}],"toggled":true},{"name":"outputs.tf","path":"outputs.tf","sha":"9d46ba8bb2ee80bf8bb1ba3ac5b7660280be3e1c"},{"name":"test","children":[{"name":"Gopkg.lock","path":"test/Gopkg.lock","sha":"568bc5956806e4aed616ba1416be9f34c6297153"},{"name":"Gopkg.toml","path":"test/Gopkg.toml","sha":"0b963bee63cabb891409e7bc306361206047d368"},{"name":"README.md","path":"test/README.md","sha":"dd3f97e937dd02cdd9142d0c25006bd6367e7fef"},{"name":"aws_helpers.go","path":"test/aws_helpers.go","sha":"f686b13f45c0deafbec5215d251c8936e30de421"},{"name":"terratest_helpers.go","path":"test/terratest_helpers.go","sha":"61cb21eeaa80d5c93a2eb1d61964991b6710a770"},{"name":"tls_helpers.go","path":"test/tls_helpers.go","sha":"9b95b015104a0c7a684f6f3af999407218121619"},{"name":"vault_cluster_auth_test.go","path":"test/vault_cluster_auth_test.go","sha":"4b86c87dd000d816af3cff34df6be83370167fe3"},{"name":"vault_cluster_autounseal_test.go","path":"test/vault_cluster_autounseal_test.go","sha":"c6a32ad54851789044b616c537770a9bd25d3e7e"},{"name":"vault_cluster_dynamodb_backend_test.go","path":"test/vault_cluster_dynamodb_backend_test.go","sha":"c2914c1ba3e7d6beda8db1c0a2b73d526b7c6155"},{"name":"vault_cluster_enterprise_test.go","path":"test/vault_cluster_enterprise_test.go","sha":"4e4aad4f69b04bf7e5233e61fd7efc107e166df0"},{"name":"vault_cluster_private_test.go","path":"test/vault_cluster_private_test.go","sha":"f115b3363e92f26f79e94e56e6551484ed74f455"},{"name":"vault_cluster_public_test.go","path":"test/vault_cluster_public_test.go","sha":"54f9497b60bb84b8383c8785ff11394abd665ba4"},{"name":"vault_cluster_s3_backend_test.go","path":"test/vault_cluster_s3_backend_test.go","sha":"4d9405cc0db461ecf249e6f4ba4098ca94066c26"},{"name":"vault_helpers.go","path":"test/vault_helpers.go","sha":"cc11523a11ece01c15173e4ae0d022cc7977751c"},{"name":"vault_main_test.go","path":"test/vault_main_test.go","sha":"9a924f09cc2959216535c3de4800535bafaffe3d"}]},{"name":"variables.tf","path":"variables.tf","sha":"c1e78c623452213f943f69d3a1fac13b3bc3d3d9"}]},"detailsContent":"<h1 class=\"preview__body--title\" id=\"private-tls-cert\">Private TLS Cert</h1><div class=\"preview__body--border\"></div><p>This module can be used to generate a Certificate Authority (CA) public key and the public and private keys of a\nTLS certificate signed by this CA. This certificate is meant to be used with <strong>private</strong> services, such as a Vault\ncluster accessed solely within your AWS account. For publicly-accessible services, especially services you access\nthrough a web browser, you should NOT use this module, and instead get certificates from a commercial Certificate\nAuthority, such as <a href=\"https://letsencrypt.org/\" class=\"preview__body--description--blue\" target=\"_blank\">Let's Encrypt</a>.</p>\n<p>If you're unfamiliar with how TLS certificates work, check out the <a href=\"#background\" class=\"preview__body--description--blue\">Background section</a>.</p>\n<h2 class=\"preview__body--subtitle\" id=\"quick-start\">Quick start</h2>\n<ol>\n<li>\n<p>Copy this module to your computer.</p>\n</li>\n<li>\n<p>Open <code>variables.tf</code> and fill in the variables that do not have a default.</p>\n</li>\n<li>\n<p>DO NOT configure Terraform remote state storage for this code. You do NOT want to store the state files as they\nwill contain the private keys for the certificates.</p>\n</li>\n<li>\n<p>Run <code>terraform apply</code>. The output will show you the paths to the generated files:</p>\n<pre>Outputs:\n\nca_public_key_file_path = ca<span class=\"hljs-selector-class\">.key</span><span class=\"hljs-selector-class\">.pem</span>\nprivate_key_file_path = vault<span class=\"hljs-selector-class\">.key</span><span class=\"hljs-selector-class\">.pem</span>\npublic_key_file_path = vault<span class=\"hljs-selector-class\">.crt</span><span class=\"hljs-selector-class\">.pem</span>\n</pre>\n</li>\n<li>\n<p>Delete your local Terraform state:</p>\n<pre>rm -rf <span class=\"hljs-keyword\">terraform</span>.tfstate*\n</pre>\n<p>The Terraform state will contain the private keys for the certificates, so it's important to clean it up!</p>\n</li>\n<li>\n<p>To inspect a certificate, you can use OpenSSL:</p>\n<pre><span class=\"hljs-selector-tag\">openssl</span> <span class=\"hljs-selector-tag\">x509</span> <span class=\"hljs-selector-tag\">-inform</span> <span class=\"hljs-selector-tag\">pem</span> <span class=\"hljs-selector-tag\">-noout</span> <span class=\"hljs-selector-tag\">-text</span> <span class=\"hljs-selector-tag\">-in</span> <span class=\"hljs-selector-tag\">vault</span><span class=\"hljs-selector-class\">.crt</span><span class=\"hljs-selector-class\">.pem</span>\n</pre>\n</li>\n</ol>\n<p>Now that you have your TLS certs, check out the next section for how to use them.</p>\n<h2 class=\"preview__body--subtitle\" id=\"using-tls-certs\">Using TLS certs</h2>\n<h3 class=\"preview__body--subtitle\" id=\"distributing-tls-certs-to-your-servers\">Distributing TLS certs to your servers</h3>\n<p>Distribute the private and public keys (the files at <code>private_key_file_path</code> and <code>public_key_file_path</code>) to the\nservers that will use them to handle TLS connections (e.g. Vault). For example, to run Vault with the <a href=\"/repos/v0.13.10/terraform-aws-vault/modules/run-vault\" class=\"preview__body--description--blue\">run-vault\nmodule</a>, you need to pass it the TLS certs:</p>\n<pre><span class=\"hljs-regexp\">/opt/</span>vault<span class=\"hljs-regexp\">/bin/</span>run-vault --tls-cert-<span class=\"hljs-keyword\">file</span> <span class=\"hljs-regexp\">/opt/</span>vault<span class=\"hljs-regexp\">/tls/</span>vault.crt.pem --tls-key-<span class=\"hljs-keyword\">file</span> <span class=\"hljs-regexp\">/opt/</span>vault<span class=\"hljs-regexp\">/tls/</span>vault.key.pem\n</pre>\n<p>We <strong>strongly</strong> recommend encrypting the private key file while it's in transit to the servers that will use it. Here\nare some of the ways you could do this:</p>\n<ul>\n<li>Encrypt the certificate using <a href=\"https://aws.amazon.com/kms/\" class=\"preview__body--description--blue\" target=\"_blank\">KMS</a> and include the encrypted files in the AMI for your\nVault servers. Give those servers an IAM role that lets them access the same KMS key and decrypt their certs just\nbefore booting.</li>\n<li>Put your TLS cert in a secure S3 Bucket with encryption enabled. Give your Vault servers an IAM role that allows them\nto download the certs from the S3 bucket just before booting.</li>\n<li>Manually upload the certificate to each EC2 Instance with <code>scp</code>.</li>\n</ul>\n<h3 class=\"preview__body--subtitle\" id=\"distributing-tls-certs-to-your-clients\">Distributing TLS certs to your clients</h3>\n<p>Distribute the CA public key (the file at <code>ca_public_key_file_path</code>) to any clients of those services so they can\nvalidate the server's TLS cert. Without the CA public key, the clients will reject any TLS connections:</p>\n<pre>vault read secret/foo\n\n<span class=\"hljs-keyword\">Error </span>initializing Vault: Get https://127.0.0.1:8200/v1/secret/foo: x509: certificate signed by unknown authority\n</pre>\n<p>Most TLS clients offer a way to explicitly specify extra public keys that you want to trust. For example, with\nVault, you do this via the <code>-ca-cert</code> argument:</p>\n<pre>vault <span class=\"hljs-keyword\">read</span> -ca-cert=ca.crt.pem secret/foo\n\nKey <span class=\"hljs-keyword\">Value</span>\n<span class=\"hljs-comment\">--- -----</span>\nrefresh_interval <span class=\"hljs-number\">768</span>h0m0s\n<span class=\"hljs-keyword\">value</span> bar\n</pre>\n<p>As an alternative, you can configure the certificate trust on your server so that all TLS clients trust your CA\npublic key by running the <a href=\"/repos/v0.13.10/terraform-aws-vault/modules/update-certificate-store\" class=\"preview__body--description--blue\">update-certificate-store module</a> on your server. Once\nyou do that, your system will trust the public key without having to pass it in explicitly:</p>\n<pre><span class=\"hljs-keyword\">update</span>-certificate-<span class=\"hljs-keyword\">store</span> <span class=\"hljs-comment\">--cert-file /opt/vault/tls/ca.crt.pem</span>\nvault <span class=\"hljs-keyword\">read</span> secret/foo\n\n<span class=\"hljs-keyword\">Key</span> <span class=\"hljs-keyword\">Value</span>\n<span class=\"hljs-comment\">--- -----</span>\nrefresh_interval <span class=\"hljs-number\">768</span>h0m0s\n<span class=\"hljs-keyword\">value</span> bar\n</pre>\n<h2 class=\"preview__body--subtitle\" id=\"background\">Background</h2>\n<h3 class=\"preview__body--subtitle\" id=\"how-tls-ssl-works\">How TLS/SSL Works</h3>\n<p>The industry-standard way to add encryption for data in motion is to use TLS (the successor to SSL). There are many\nexamples online explaining how TLS works, but here are the basics:</p>\n<ul>\n<li>\n<p>Some entity decides to be a "Certificate Authority" ("CA") meaning it will issue TLS certificates to websites or\nother services</p>\n</li>\n<li>\n<p>An entity becomes a Certificate Authority by creating a public/private key pair and publishing the public portion\n(typically known as the "CA Cert"). The private key is kept under the tightest possible security since anyone who\npossesses it could issue TLS certificates as if they were this Certificate Authority!</p>\n</li>\n<li>\n<p>In fact, the consequences of a CA's private key being compromised are so disastrous that CA's typically create an\n"intermediate" CA keypair with their "root" CA key, and only issue TLS certificates with the intermediate key.</p>\n</li>\n<li>\n<p>Your client (e.g. a web browser) can decide to trust this newly created Certificate Authority by including its CA\nCert (the CA's public key) when making an outbound request to a service that uses the TLS certificate.</p>\n</li>\n<li>\n<p>When CAs issue a TLS certificate ("TLS cert") to a service, they again create a public/private keypair, but this time\nthe public key is "signed" by the CA. That public key is what you view when you click on the lock icon in a web\nbrowser and what a service "advertises" to any clients such as web browsers to declare who it is. When we say that\nthe CA signed a public key, we mean that, cryptographically, any possessor of the CA Cert can validate that this same\nCA issued this particular public key.</p>\n</li>\n<li>\n<p>The public key is more generally known as the TLS cert.</p>\n</li>\n<li>\n<p>The private key created by the CA must be kept secret by the service since the possessor of the private key can\n"prove" they are whoever the TLS cert (public key) claims to be as part of the TLS protocol.</p>\n</li>\n<li>\n<p>How does that "proof" work? Well, your web browser will attempt to validate the TLS cert in two ways:</p>\n<ul>\n<li>First, it will ensure this public key (TLS cert) is in fact signed by a CA it trusts.</li>\n<li>Second, using the TLS protocol, your browser will encrypt a message with the public key (TLS cert) that only the\npossessor of the corresponding private key can decrypt. In this manner, your browser will be able to come up with a\nsymmetric encryption key it can use to encrypt all traffic for just that one web session.</li>\n</ul>\n</li>\n<li>\n<p>Now your client/browser has:</p>\n<ul>\n<li>declared which CA it will trust</li>\n<li>verified that the service it's connecting to possesses a certificate issued by a CA it trusts</li>\n<li>used that service's public key (TLS cert) to establish a secure session</li>\n</ul>\n</li>\n</ul>\n<h3 class=\"preview__body--subtitle\" id=\"commercial-or-public-certificate-authorities\">Commercial or Public Certificate Authorities</h3>\n<p>For public services like banks, healthcare, and the like, it makes sense to use a "Commercial CA" like Verisign, Thawte,\nor Digicert, or better yet a widely trusted but free service like <a href=\"https://letsencrypt.org/\" class=\"preview__body--description--blue\" target=\"_blank\">Let's Encrypt</a>. That's\nbecause every web browser comes pre-configured with a set of CA's that it trusts. This means the client connecting to\nthe bank doesn't have to know anything about CA's at all. Instead, their web browser is configured to trust the CA that\nhappened to issue the bank's certificate.</p>\n<p>Connecting securely to private services is similar to connecting to your bank's website over TLS, with one primary\ndifference: <strong>We want total control over the CA.</strong></p>\n<p>Imagine if we used a commercial CA to issue our private TLS certificate and that commercial or public CA--which we\ndon't control--were compromised. Now the attackers of that commercial or public CA could impersonate our private server.\nAnd indeed, <a href=\"https://www.theguardian.com/technology/2011/sep/05/diginotar-certificate-hack-cyberwar\" class=\"preview__body--description--blue\" target=\"_blank\">it</a> <a href=\"https://www.schneier.com/blog/archives/2012/02/verisign_hacked.html\" class=\"preview__body--description--blue\" target=\"_blank\">has</a> <a href=\"http://www.infoworld.com/article/2623707/hacking/the-real-security-issue-behind-the-comodo-hack.html\" class=\"preview__body--description--blue\" target=\"_blank\">happened</a>\nmultiple times.</p>\n<h3 class=\"preview__body--subtitle\" id=\"how-well-generate-a-tls-cert-for-private-services\">How We'll Generate a TLS Cert for Private Services</h3>\n<p>One option is to be very selective about choosing a commercial CA, but to what benefit? What we want instead is\nassurance that our private service really was launched by people we trust. Those same people--let's call them our\n"operators"--can become their <em>own</em> CA and generate their <em>own</em> TLS certificate for the private service.</p>\n<p>Sure, no one else in the world will trust this CA, but we don't care because we only need our organization to trust\nthis CA.</p>\n<p>So here's our strategy for issuing a TLS Cert for a private service:</p>\n<ol>\n<li>\n<p><strong>Create our own CA.</strong></p>\n<ul>\n<li>If a client wishes to trust our CA, they need only reference this CA public key.</li>\n<li>We'll deal with the private key in a moment.</li>\n</ul>\n</li>\n<li>\n<p><strong>Using our CA, issue a TLS Certificate for our private service.</strong></p>\n<ul>\n<li>Create a public/private key pair for the private service, and have the CA sign the public key.</li>\n<li>This means anyone who trusts the CA will trust that the possessor of the private key that corresponds to this public\nkey is who they claim to be.</li>\n<li>We will be extremely careful with the TLS private key since anyone who obtains it can impersonate our private\nservice! For this reason, we recommend immediately encrypting the private key with\n<a href=\"https://aws.amazon.com/kms/\" class=\"preview__body--description--blue\" target=\"_blank\">KMS</a>.</li>\n</ul>\n</li>\n<li>\n<p><strong>Freely advertise our CA's public key to all internal services.</strong></p>\n<ul>\n<li>Any service that wishes to connect securely to our private service will need our CA's public key so it can declare\nthat it trusts this CA, and thereby the TLS cert it issued to the private service.</li>\n</ul>\n</li>\n<li>\n<p><strong>Throw away the CA private key.</strong></p>\n<ul>\n<li>By erasing a CA private key it's impossible for the CA to be compromised, because there's no private key to steal!</li>\n<li>Future certs can be generated with a new CA.</li>\n</ul>\n</li>\n</ol>\n","repoName":"terraform-aws-vault","repoRef":"v0.13.8","serviceDescriptor":{"serviceName":"HashiCorp Vault","serviceRepoName":"terraform-aws-vault","serviceRepoOrg":"hashicorp","cloudProviders":["aws"],"description":"Deploy a Vault cluster. Supports automatic bootstrapping, Consul and S3 backends, self-signed TLS certificates, and auto healing.","imageUrl":"vault.png","licenseType":"open-source","technologies":["Terraform","Bash"],"compliance":[],"tags":[""]},"serviceCategoryName":"Secrets management","fileName":"README.md","filePath":"/modules/private-tls-cert","title":"Repo Browser: HashiCorp Vault","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}