This example shows how to use the metadata from an EC2 instance to authenticate
to a vault cluster.
Vault provides multiple ways to authenticate a human or machine to Vault, known as
auth methods. For example, a human can authenticate with a Username
& Password or with GitHub.
Among those methods you will find AWS. The way it works is that Vault
understands AWS as a trusted third party, and relies on AWS itself for affirming
if an authentication source such as an EC2 Instance or other resources like a Lambda
Function are legitimate sources or not.
There are currently two ways an AWS resource can authenticatate to Vault: ec2 and iam.
In this example, we demonstrate the AWS EC2 Auth Method.
Note: To keep this example as simple to deploy and test as possible and because we are
focusing on authentication, it deploys the Vault cluster into your default VPC and default subnets,
all of which are publicly accessible. This is OK for learning and experimenting, but for
production usage, we strongly recommend deploying the Vault cluster into the private subnets
of a custom VPC.
Running this example
You will need to create an Amazon Machine Image (AMI) that has both Vault and Consul
installed, which you can do using the vault-consul-ami example). All the EC2
Instances in this example (including the EC2 Instance that authenticates to Vault) install
Dnsmasq (via the install-dnsmasq module) or
setup-systemd-resolved (in the case of Ubuntu 18.04) so that all DNS queries
for *.consul will be directed to the Consul Server cluster. Because Consul has knowledge of
all the Vault nodes (and in some cases, of other services as well), this setup allows the EC2
Instance to use Consul's DNS server for service discovery, and thereby to discover the IP addresses
of the Vault nodes.
Quick start
git clone this repo to your computer.
Build a Vault and Consul AMI. See the vault-consul-ami example documentation for
instructions. Make sure to note down the ID of the AMI.
Open variables.tf, set the environment variables specified at the top of the file, and fill in any other variables that
don't have a default. Put the AMI ID you previously took note into the ami_id variable.
Run terraform init.
Run terraform apply.
Run the vault-examples-helper.sh script to
print out the IP addresses of the Vault server and some example commands you can run to interact with the cluster:
../vault-examples-helper/vault-examples-helper.sh.
Run curl <auth-instance-ip>:8080 to check if the client instance is fetching the secret from Vault properly
EC2 Auth
EC2 auth is a process in which Vault relies on information about an EC2 instance
trying to assume a desired authentication role. For different resources that are
not EC2 instances, please refer to the iam auth method example.
The workflow is that the client trying to authenticate itself will send a
signature in its login request, Vault verifies the signature with AWS, checks
against a predefined authentication role, then returns a client token that the
client can use for making future requests to vault. More details about the
signature and how this works at the section authenticating from an
instance
It is important to notice that, once the server receives a login request with a
signature, to be able to verify it against AWS and check the instance
metadata information, the vault server needs to be allowed to do certain
operations on AWS such as ec2:DescribeInstances. On this example, we use the
same policy defined for Consul since it also has these
permissions.
Configuring a Vault server
Before we try to authenticate, we must be sure that the Vault Server is configured
properly and prepared to receive requests. First, we must make sure the Vault server
has been initialized (using vault operator init) and unsealed (using vault operator unseal).
Next, we must enable Vault to support the AWS auth method (using vault auth enable aws).
After that, we enable the Vault kv secrets engine at the path secret (note that this engine
was enabled by default in previous versions < 1.1.0). Finally, we must define the correct
Vault Policies and Roles to declare which IAM Principals will have access to which resources
in Vault.
Policies are rules that grant or forbid access and actions to certain paths in
Vault. With one or more policies on hand, you can then finally create the authentication role.
When you create a Role in Vault, you define the Policies that are attached to that
Role, how principals who assume that Role will re-authenticate, and for how long
tokens issued for that role will be valid. When your Role uses the EC2 AWS Auth
method, you also specify which of the EC2 Instance Metadata properties will be
required by the principal (in this case, the EC2 Instance) in order to successfully
authenticate.
In our example we create a simple Vault Policy that allows writing and reading from
secrets in the path secret namespaced with the prefix example_, and then create
a Vault Role that allows authentication from all instances with a specific ami id.
You can read more about Role creation and check which other instance metadata you can
use on auth here.
The signature used to authenticate to Vault is a PKCS7 certificate that is part of the AWS
Instance Identity Document. This certificate can be fetched from the EC2
metadata API with $(curl -s http://169.254.169.254/latest/dynamic/instance-identity/pkcs7 | tr -d '\n')
and will then be part of the body of data sent with the login request.
The Instance Identity Document describes various features of the EC2 Instance like its Instance Type,
region, IAM Role and a "signature" for this document that is signed by AWS. The signature can be used
to prove that the Instance Identity Document was produced by AWS, and not a malicious third party. By
sending the Instance Identity Document and signature to Vault, you are proving to Vault that you are
an EC2 Instance that genuinely has the properties described in the Instance Identity Document. Vault
can then use these properties to help decide whether to authenticate you.
After sending the login request to Vault, Vault will verify it against AWS and
return a JSON object with your login information. This JSON contains two
important values: the client_token and the nonce. The client token is an
ephemeral token that you will send with your future operations requests to
Vault. It can expire, be rotated, or become invalid for some other reason and
you will be required to authenticate again.
However, as a security measure, Vault operates with a TOFU (Trust on First Use)
mechanism. That means that once an instance logins, all other logins with the
same signature will fail. The reason is to prevent unintended logins in case the
PKCS7 signature gets compromised by another process in the instance. For this
reason, when the instance does its first login, it also receives a cryptographic
nonce (number used once) and this nonce has to be provided in the future
login attempts. Only one unique principal (i.e. one unique EC2 Instance ID) can
use that nonce.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"be1841a927697869a942fb91e86672c646cc32bb"}]},{"name":".gitignore","path":".gitignore","sha":"6c4ebe4426586b7febbaba178294ef59b8272c05"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"5949dbc0fa6d4dd6610575e3c878c353d92da44a"},{"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":"ca0abbac27030e0041b221b8c96b68868615d46c"},{"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":"34fc05d0337fd83fdb42faa143e6b216a8f6585b"}]},{"name":"vault-ec2-auth","children":[{"name":"README.md","path":"examples/vault-ec2-auth/README.md","sha":"29af1121fa99b3903b09447c79e127daecb30bfb","toggled":true},{"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"}],"toggled":true},{"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"}]}],"toggled":true},{"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"},{"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"}]},{"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":"192feb7aa74fde7c93df0e091352780adfeb46c4"}]},{"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":"d8e6b486f28dc2fc35591d7389e6b2ad4d4bf4df"},{"name":"outputs.tf","path":"modules/vault-cluster/outputs.tf","sha":"ab03f0accf81c6722c79656844acd1fd39b41e87"},{"name":"variables.tf","path":"modules/vault-cluster/variables.tf","sha":"4067580ffe82b3c9aaf558887c413ba2992e9394"}]},{"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"}]}]},{"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":"6dc38ca9feb145131336742a05305a63716a663d"},{"name":"vault_cluster_autounseal_test.go","path":"test/vault_cluster_autounseal_test.go","sha":"6378645baf5b1882e25cc1a9a6ea33c2a499670a"},{"name":"vault_cluster_enterprise_test.go","path":"test/vault_cluster_enterprise_test.go","sha":"4b2ca281392b651c889ea0a6f9b4c4afb703ddee"},{"name":"vault_cluster_private_test.go","path":"test/vault_cluster_private_test.go","sha":"9b4c9c7e3c58a9b87df4ab34952b9f908f890f1b"},{"name":"vault_cluster_public_test.go","path":"test/vault_cluster_public_test.go","sha":"adeceaf1a85f323c920117c27992048335bd38a8"},{"name":"vault_cluster_s3_backend_test.go","path":"test/vault_cluster_s3_backend_test.go","sha":"cb028cf873c350aeb24bf5b01e9574790cf2fddb"},{"name":"vault_helpers.go","path":"test/vault_helpers.go","sha":"68cf62618b5510e55577780c65b48528c39a2c44"},{"name":"vault_main_test.go","path":"test/vault_main_test.go","sha":"905a37d2df09a4053104f163ddbd8d0d8bbab28d"}]},{"name":"variables.tf","path":"variables.tf","sha":"c1e78c623452213f943f69d3a1fac13b3bc3d3d9"}]},"detailsContent":"<h1 class=\"preview__body--title\" id=\"vault-authentication-using-ec-2-metadata-example\">Vault authentication using EC2 metadata example</h1><div class=\"preview__body--border\"></div><p>This example shows how to use the metadata from an EC2 instance to authenticate\nto a <a href=\"/repos/v0.16.0/terraform-aws-vault/modules/vault-cluster\" class=\"preview__body--description--blue\">vault cluster</a>.</p>\n<p>Vault provides multiple ways to authenticate a human or machine to Vault, known as\n<a href=\"https://www.vaultproject.io/docs/auth/index.html\" class=\"preview__body--description--blue\" target=\"_blank\">auth methods</a>. For example, a human can authenticate with a Username\n& Password or with GitHub.</p>\n<p>Among those methods you will find <a href=\"https://www.vaultproject.io/docs/auth/aws.html\" class=\"preview__body--description--blue\" target=\"_blank\">AWS</a>. The way it works is that Vault\nunderstands AWS as a trusted third party, and relies on AWS itself for affirming\nif an authentication source such as an EC2 Instance or other resources like a Lambda\nFunction are legitimate sources or not.</p>\n<p>There are currently two ways an AWS resource can authenticatate to Vault: <code>ec2</code> and <code>iam</code>.\nIn this example, we demonstrate the <a href=\"https://www.vaultproject.io/docs/auth/aws.html#ec2-auth-method\" class=\"preview__body--description--blue\" target=\"_blank\">AWS EC2 Auth Method</a>.</p>\n<p><strong>Note</strong>: To keep this example as simple to deploy and test as possible and because we are\nfocusing on authentication, it deploys the Vault cluster into your default VPC and default subnets,\nall of which are publicly accessible. This is OK for learning and experimenting, but for\nproduction usage, we strongly recommend deploying the Vault cluster into the private subnets\nof a custom VPC.</p>\n<h2 class=\"preview__body--subtitle\" id=\"running-this-example\">Running this example</h2>\n<p>You will need to create an <a href=\"http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html\" class=\"preview__body--description--blue\" target=\"_blank\">Amazon Machine Image (AMI)</a> that has both Vault and Consul\ninstalled, which you can do using the <a href=\"/repos/v0.16.0/terraform-aws-vault/examples/vault-consul-ami\" class=\"preview__body--description--blue\">vault-consul-ami example</a>). All the EC2\nInstances in this example (including the EC2 Instance that authenticates to Vault) install\n<a href=\"http://www.thekelleys.org.uk/dnsmasq/doc.html\" class=\"preview__body--description--blue\" target=\"_blank\">Dnsmasq</a> (via the <a href=\"/repos/terraform-aws-consul/modules/install-dnsmasq\" class=\"preview__body--description--blue\">install-dnsmasq module</a>) or\n<a href=\"/repos/terraform-aws-consul/modules/setup-systemd-resolved\" class=\"preview__body--description--blue\">setup-systemd-resolved</a> (in the case of Ubuntu 18.04) so that all DNS queries\nfor <code>*.consul</code> will be directed to the Consul Server cluster. Because Consul has knowledge of\nall the Vault nodes (and in some cases, of other services as well), this setup allows the EC2\nInstance to use Consul's DNS server for service discovery, and thereby to discover the IP addresses\nof the Vault nodes.</p>\n<h3 class=\"preview__body--subtitle\" id=\"quick-start\">Quick start</h3>\n<ol>\n<li><code>git clone</code> this repo to your computer.</li>\n<li>Build a Vault and Consul AMI. See the <a href=\"/repos/v0.16.0/terraform-aws-vault/examples/vault-consul-ami\" class=\"preview__body--description--blue\">vault-consul-ami example</a> documentation for\ninstructions. Make sure to note down the ID of the AMI.</li>\n<li>Install <a href=\"https://www.terraform.io/\" class=\"preview__body--description--blue\" target=\"_blank\">Terraform</a>.</li>\n<li>Open <code>variables.tf</code>, set the environment variables specified at the top of the file, and fill in any other variables that\ndon't have a default. Put the AMI ID you previously took note into the <code>ami_id</code> variable.</li>\n<li>Run <code>terraform init</code>.</li>\n<li>Run <code>terraform apply</code>.</li>\n<li>Run the <a href=\"/repos/v0.16.0/terraform-aws-vault/examples/vault-examples-helper/vault-examples-helper.sh\" class=\"preview__body--description--blue\">vault-examples-helper.sh script</a> to\nprint out the IP addresses of the Vault server and some example commands you can run to interact with the cluster:\n<code>../vault-examples-helper/vault-examples-helper.sh</code>.</li>\n<li>Run <code>curl <auth-instance-ip>:8080</code> to check if the client instance is fetching the secret from Vault properly</li>\n</ol>\n<h2 class=\"preview__body--subtitle\" id=\"ec-2-auth\">EC2 Auth</h2>\n<p>EC2 auth is a process in which Vault relies on information about an EC2 instance\ntrying to assume a desired authentication role. For different resources that are\nnot EC2 instances, please refer to the <a href=\"/repos/v0.16.0/terraform-aws-vault/examples/vault-iam-auth\" class=\"preview__body--description--blue\"><code>iam</code> auth method example</a>.</p>\n<p>The workflow is that the client trying to authenticate itself will send a\nsignature in its login request, Vault verifies the signature with AWS, checks\nagainst a predefined authentication role, then returns a client token that the\nclient can use for making future requests to vault. More details about the\nsignature and how this works at the section <a href=\"#authenticating-from-an-instance\" class=\"preview__body--description--blue\">authenticating from an\ninstance</a></p>\n<p><img src=\"/repos/images/v0.16.0/terraform-aws-vault/examples/vault-ec2-auth/images/ec2-auth.png\" alt=\"auth diagram\" class=\"preview__body--diagram\"></p>\n<p>It is important to notice that, once the server receives a login request with a\nsignature, to be able to verify it against AWS and check the instance\nmetadata information, the vault server needs to be allowed to do certain\noperations on AWS such as <code>ec2:DescribeInstances</code>. On this example, we use the\nsame <a href=\"/repos/terraform-aws-consul/modules/consul-iam-policies/main.tf\" class=\"preview__body--description--blue\">policy</a> defined for <code>Consul</code> since it also has these\npermissions.</p>\n<h3 class=\"preview__body--subtitle\" id=\"configuring-a-vault-server\">Configuring a Vault server</h3>\n<p>Before we try to authenticate, we must be sure that the Vault Server is configured\nproperly and prepared to receive requests. First, we must make sure the Vault server\nhas been initialized (using <code>vault operator init</code>) and unsealed (using <code>vault operator unseal</code>).\nNext, we must enable Vault to support the AWS auth method (using <code>vault auth enable aws</code>).\nAfter that, we enable the Vault kv secrets engine at the path <code>secret</code> (note that this engine\nwas enabled by default in previous versions < 1.1.0). Finally, we must define the correct\nVault Policies and Roles to declare which IAM Principals will have access to which resources\nin Vault.</p>\n<p><a href=\"https://www.vaultproject.io/docs/concepts/policies.html\" class=\"preview__body--description--blue\" target=\"_blank\">Policies</a> are rules that grant or forbid access and actions to certain paths in\nVault. With one or more policies on hand, you can then finally create the authentication role.</p>\n<p>When you create a Role in Vault, you define the Policies that are attached to that\nRole, how principals who assume that Role will re-authenticate, and for how long\ntokens issued for that role will be valid. When your Role uses the EC2 AWS Auth\nmethod, you also specify which of the EC2 Instance Metadata properties will be\nrequired by the principal (in this case, the EC2 Instance) in order to successfully\nauthenticate.</p>\n<p>In our example we create a simple Vault Policy that allows writing and reading from\nsecrets in the path <code>secret</code> namespaced with the prefix <code>example_</code>, and then create\na Vault Role that allows authentication from all instances with a specific <code>ami id</code>.\nYou can read more about Role creation and check which other instance metadata you can\nuse on auth <a href=\"https://www.vaultproject.io/api/auth/aws/index.html#create-role\" class=\"preview__body--description--blue\" target=\"_blank\">here</a>.</p>\n<pre>vault<span class=\"hljs-built_in\"> policy </span>write <span class=\"hljs-string\">\"example-policy\"</span> -<<EOF\npath <span class=\"hljs-string\">\"secret/example_*\"</span> {\n capabilities = [<span class=\"hljs-string\">\"create\"</span>, <span class=\"hljs-string\">\"read\"</span>]\n}\nEOF\n\nvault write \\\n auth/aws/role/example-role\n <span class=\"hljs-attribute\">auth_type</span>=ec2 \\\n <span class=\"hljs-attribute\">policies</span>=example-policy \\\n <span class=\"hljs-attribute\">max_ttl</span>=500h \\\n <span class=\"hljs-attribute\">bound_ami_id</span>=<span class=\"hljs-variable\">$ami_id</span>\n</pre>\n<p>See the whole example script at <a href=\"/repos/v0.16.0/terraform-aws-vault/examples/vault-ec2-auth/user-data-vault.sh\" class=\"preview__body--description--blue\">user-data-vault.sh</a>.</p>\n<h3 class=\"preview__body--subtitle\" id=\"authenticating-from-an-instance\">Authenticating from an instance</h3>\n<p>The signature used to authenticate to Vault is a PKCS7 certificate that is part of the AWS\n<a href=\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html\" class=\"preview__body--description--blue\" target=\"_blank\">Instance Identity Document</a>. This certificate can be fetched from the EC2\nmetadata API with <code>$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/pkcs7 | tr -d '\\n')</code>\nand will then be part of the body of data sent with the login request.</p>\n<p>The Instance Identity Document describes various features of the EC2 Instance like its Instance Type,\nregion, IAM Role and a "signature" for this document that is signed by AWS. The signature can be used\nto prove that the Instance Identity Document was produced by AWS, and not a malicious third party. By\nsending the Instance Identity Document and signature to Vault, you are proving to Vault that you are\nan EC2 Instance that genuinely has the properties described in the Instance Identity Document. Vault\ncan then use these properties to help decide whether to authenticate you.</p>\n<pre><span class=\"hljs-keyword\">data</span>=$(cat <<EOF\n{\n <span class=\"hljs-string\">\"role\"</span>: <span class=\"hljs-string\">\"example-role\"</span>,\n <span class=\"hljs-string\">\"pkcs7\"</span>: <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$pkcs7</span>\"</span>\n}\nEOF\n)\ncurl --request POST --<span class=\"hljs-keyword\">data</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$data</span>\"</span> <span class=\"hljs-string\">\"https://vault.service.consul:8200/v1/auth/aws/login\"</span>\n</pre>\n<p>After sending the login request to Vault, Vault will verify it against AWS and\nreturn a JSON object with your login information. This JSON contains two\nimportant values: the <code>client_token</code> and the <code>nonce</code>. The client token is an\nephemeral token that you will send with your future operations requests to\nVault. It can expire, be rotated, or become invalid for some other reason and\nyou will be required to authenticate again.</p>\n<p>However, as a security measure, Vault operates with a TOFU (Trust on First Use)\nmechanism. That means that once an instance logins, all other logins with the\nsame signature will fail. The reason is to prevent unintended logins in case the\nPKCS7 signature gets compromised by another process in the instance. For this\nreason, when the instance does its first login, it also receives a cryptographic\n<code>nonce</code> (number used once) and this <code>nonce</code> has to be provided in the future\nlogin attempts. Only one unique principal (i.e. one unique EC2 Instance ID) can\nuse that nonce.</p>\n<pre><span class=\"hljs-keyword\">data</span>=$(cat <<EOF\n{\n <span class=\"hljs-string\">\"role\"</span>: <span class=\"hljs-string\">\"example-role\"</span>,\n <span class=\"hljs-string\">\"pkcs7\"</span>: <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$pkcs7</span>\"</span>,\n <span class=\"hljs-string\">\"nonce\"</span>: <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$nonce</span>\"</span>\n}\nEOF\n)\ncurl --request POST --<span class=\"hljs-keyword\">data</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$data</span>\"</span> <span class=\"hljs-string\">\"https://vault.service.consul:8200/v1/auth/aws/login\"</span>\n</pre>\n<p>It is up to the client to decide how it handles the nonce. To read more about\nit, refer to the <a href=\"https://www.vaultproject.io/docs/auth/aws.html#client-nonce\" class=\"preview__body--description--blue\" target=\"_blank\">Vault documentation on client nonce</a>.</p>\n<p>To see the full script for authenticating check the <a href=\"/repos/v0.16.0/terraform-aws-vault/examples/vault-ec2-auth/user-data-auth-client.sh\" class=\"preview__body--description--blue\">client user data script</a>.</p>\n","repoName":"terraform-aws-vault","repoRef":"v0.13.4","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":"/examples/vault-ec2-auth","title":"Repo Browser: HashiCorp Vault","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}