From 3b4df0395cbde2485adb4527f15d0ebdfe6ae10e Mon Sep 17 00:00:00 2001 From: Sibi Prabakaran Date: Fri, 12 Jul 2019 01:08:49 +0530 Subject: [PATCH] WIP: Vault and IAM integration --- examples/vault-s3-private/Makefile | 49 ++++++++++ examples/vault-s3-private/README.md | 128 +++++++++++++++++++++++++ examples/vault-s3-private/main.tf | 67 +++++++++++++ examples/vault-s3-private/variables.tf | 56 +++++++++++ modules/vault-aws-backend/README.md | 6 ++ modules/vault-aws-backend/main.tf | 25 +++++ modules/vault-aws-backend/variables.tf | 55 +++++++++++ modules/vault-iam/Makefile | 43 +++++++++ modules/vault-iam/README.md | 7 ++ modules/vault-iam/main.tf | 44 +++++++++ modules/vault-iam/outputs.tf | 7 ++ 11 files changed, 487 insertions(+) create mode 100644 examples/vault-s3-private/Makefile create mode 100644 examples/vault-s3-private/README.md create mode 100644 examples/vault-s3-private/main.tf create mode 100644 examples/vault-s3-private/variables.tf create mode 100644 modules/vault-aws-backend/README.md create mode 100644 modules/vault-aws-backend/main.tf create mode 100644 modules/vault-aws-backend/variables.tf create mode 100644 modules/vault-iam/Makefile create mode 100644 modules/vault-iam/README.md create mode 100644 modules/vault-iam/main.tf create mode 100644 modules/vault-iam/outputs.tf diff --git a/examples/vault-s3-private/Makefile b/examples/vault-s3-private/Makefile new file mode 100644 index 00000000..3694c5c4 --- /dev/null +++ b/examples/vault-s3-private/Makefile @@ -0,0 +1,49 @@ +.PHONY: init plan apply destroy clean + +.DEFAULT_GOAL = help + +# Hardcoding value of 3 minutes when we check if the plan file is stale +STALE_PLAN_FILE := `find "tf.out" -mmin -3 | grep -q tf.out` + +## Check if tf.out is stale (Older than 2 minutes) +check-plan-file: + @if ! ${STALE_PLAN_FILE} ; then \ + echo "ERROR: Stale tf.out plan file (older than 3 minutes)!"; \ + exit 1; \ + fi + +## Runs terraform get and terraform init for env +init: + @terraform get + @terraform init + +## use 'terraform plan' to map out updates to apply +plan: + @terraform plan -out=tf.out + +## use 'terraform apply' to apply updates in a 'tf.out' plan file +apply: check-plan-file + @terraform apply tf.out + +## use 'terraform destroy' to remove all resources from AWS +destroy: + @terraform destroy + +## rm -rf all files and state +clean: + @rm -f tf.out + @rm -f terraform.*.backup + @rm -f terraform.tfstate + +## Show help screen. +help: + @echo "Please use \`make ' where is one of\n\n" + @awk '/^[a-zA-Z\-\_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf "%-30s %s\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) diff --git a/examples/vault-s3-private/README.md b/examples/vault-s3-private/README.md new file mode 100644 index 00000000..8bb524ff --- /dev/null +++ b/examples/vault-s3-private/README.md @@ -0,0 +1,128 @@ +# Example showing Vault and IAM Integration + +This example creates a private s3 bucket resources. It then uses vault +to create keys which only has access to those s3 buckets. The example +code will create an IAM role with access to that bucket and will also +configure vault so that we can dynamically generate credentials for +accessing that bucket. + +## Requirements + +These are the required things for this example: + +* A running vault server. If you just want to experiment with this, + run a development server using: + +``` shellsession +vault server -dev +``` + +* The AWS access and secret keys for an IAM user which the AWS Secret + Backend for Vault will use for issuing new credentials. If you don't + have any, you can create one using [vault-iam + module](../../modules/vault-iam). You need to put the access keys in + [variables.tf](./variables.tf) + + +## Environment creation and deployment + +``` shellsession +$ make init +$ make plan +$ make apply +module.vault_aws_backend.vault_aws_secret_backend.aws: Creating... +module.vault_aws_backend.vault_aws_secret_backend.aws: Creation complete after 0s [id=fpco/aws/dev/vault] +aws_iam_role.vault_bucket_role: Creating... +aws_s3_bucket.vault-test-bucket: Creating... +aws_iam_role.vault_bucket_role: Still creating... [10s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [10s elapsed] +aws_iam_role.vault_bucket_role: Still creating... [20s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [20s elapsed] +aws_iam_role.vault_bucket_role: Creation complete after 22s [id=bucket_access_role] +module.vault_aws_backend.vault_aws_secret_backend_role.aws_role: Creating... +module.vault_aws_backend.vault_aws_secret_backend_role.aws_role: Creation complete after 0s [id=fpco/aws/dev/vault/roles/s3_app_user] +aws_s3_bucket.vault-test-bucket: Still creating... [30s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [40s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [50s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [1m0s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [1m10s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [1m20s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [1m30s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [1m40s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [1m50s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [2m0s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [2m10s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [2m20s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [2m30s elapsed] +aws_s3_bucket.vault-test-bucket: Still creating... [2m40s elapsed] +aws_s3_bucket.vault-test-bucket: Creation complete after 2m48s [id=vault-fpco-test-bucket] +aws_iam_role_policy.vault_bucket_policy: Creating... +aws_iam_role_policy.vault_bucket_policy: Still creating... [10s elapsed] +aws_iam_role_policy.vault_bucket_policy: Still creating... [20s elapsed] +aws_iam_role_policy.vault_bucket_policy: Creation complete after 24s [id=bucket_access_role:bucket-policy] + +Apply complete! Resources: 5 added, 0 changed, 0 destroyed. + +The state of your infrastructure has been saved to the path +below. This state is required to modify and destroy your +infrastructure, so keep it safe. To inspect the complete state +use the `terraform show` command. + +State path: terraform.tfstate +``` + +## Testing + +Make sure you are already authorized with the vault server. If not, +use `vault login` to do it. And then, you can dynamically create AWS +credentials for accessing the s3 bucket you created: + +``` shellsession +$ vault read fpco/aws/dev/vault/creds/s3_app_user +Key Value +--- ----- +lease_id fpco/aws/prod/vault/creds/s3_app_user/eJcLUNbpTNRFpLoTL9mEW76p +lease_duration 14m59s +lease_renewable false +access_key xxx +secret_key xxx +security_token xxx +``` + +Now let's try to see all the files in our bucket: + +``` shellsession +$ env AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx aws s3 ls s3://vault-fpco-test-bucket +``` + +It gives you no output since there are no files. But the command +works, which confirms us that the generated credentials are working as +expected. + +Now let's try to do something for which you don't have access with the +same credentials: + +``` shellsession +$ env AWS_ACCESS_KEY_ID=xxxx AWS_SECRET_ACCESS_KEY=xxxx AWS_SESSION_TOKEN=xxx aws ec2 describe-instances --region="us-east-2" +An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation. +``` + +That doesn't work, which is expected. Let's try to see if we can +access files of some other buckets which is present: + +``` shellsession +$ env AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx aws s3 ls s3://some-other-existing-bucket +An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied +``` + +## Destruction + +``` shellsession +$ make destroy +$ make clean +``` + +## Notes + +- This example was last tested with `Terraform v0.12.3` +- This example assumes AWS credentials setup with access to the **us-east-2** region. diff --git a/examples/vault-s3-private/main.tf b/examples/vault-s3-private/main.tf new file mode 100644 index 00000000..f16ac0dd --- /dev/null +++ b/examples/vault-s3-private/main.tf @@ -0,0 +1,67 @@ +resource "aws_s3_bucket" "vault-test-bucket" { + bucket = "vault-fpco-test-bucket" + acl = "private" + region = "us-east-2" + + tags = { + Name = "Vault test bucket" + Environment = "Dev" + } +} + +# Here we allow everyone to assume this role. In production systems +# it's best to restrict it's scope so that only some IAM users are +# able to assume this role. +resource "aws_iam_role" "vault_bucket_role" { + name = "bucket_access_role" + + assume_role_policy = <' where is one of\n\n" + @awk '/^[a-zA-Z\-\_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf "%-30s %s\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) diff --git a/modules/vault-iam/README.md b/modules/vault-iam/README.md new file mode 100644 index 00000000..0103b046 --- /dev/null +++ b/modules/vault-iam/README.md @@ -0,0 +1,7 @@ +# Vault IAM user + +When setting up vault with AWS as it's secret engine, you need to have +AWS secret and access keys for an IAM user with relevant +permission. This module sets up the user with relevant policies. + +Todo: Try with different resour4ce diff --git a/modules/vault-iam/main.tf b/modules/vault-iam/main.tf new file mode 100644 index 00000000..630b9ae4 --- /dev/null +++ b/modules/vault-iam/main.tf @@ -0,0 +1,44 @@ +resource "aws_iam_user" "vault_user" { + name = "vault_user" + tags = { + "user" = "vault" + } +} + +resource "aws_iam_access_key" "vaultkey" { + user = "${aws_iam_user.vault_user.name}" +} + +resource "aws_iam_user_policy" "vault_user_policy" { + name = "vault_user_policy" + user = "${aws_iam_user.vault_user.name}" + + policy = <