Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit 3b4df03

Browse files
committed
WIP: Vault and IAM integration
1 parent 0d3d60f commit 3b4df03

File tree

11 files changed

+487
-0
lines changed

11 files changed

+487
-0
lines changed

examples/vault-s3-private/Makefile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
.PHONY: init plan apply destroy clean
2+
3+
.DEFAULT_GOAL = help
4+
5+
# Hardcoding value of 3 minutes when we check if the plan file is stale
6+
STALE_PLAN_FILE := `find "tf.out" -mmin -3 | grep -q tf.out`
7+
8+
## Check if tf.out is stale (Older than 2 minutes)
9+
check-plan-file:
10+
@if ! ${STALE_PLAN_FILE} ; then \
11+
echo "ERROR: Stale tf.out plan file (older than 3 minutes)!"; \
12+
exit 1; \
13+
fi
14+
15+
## Runs terraform get and terraform init for env
16+
init:
17+
@terraform get
18+
@terraform init
19+
20+
## use 'terraform plan' to map out updates to apply
21+
plan:
22+
@terraform plan -out=tf.out
23+
24+
## use 'terraform apply' to apply updates in a 'tf.out' plan file
25+
apply: check-plan-file
26+
@terraform apply tf.out
27+
28+
## use 'terraform destroy' to remove all resources from AWS
29+
destroy:
30+
@terraform destroy
31+
32+
## rm -rf all files and state
33+
clean:
34+
@rm -f tf.out
35+
@rm -f terraform.*.backup
36+
@rm -f terraform.tfstate
37+
38+
## Show help screen.
39+
help:
40+
@echo "Please use \`make <target>' where <target> is one of\n\n"
41+
@awk '/^[a-zA-Z\-\_0-9]+:/ { \
42+
helpMessage = match(lastLine, /^## (.*)/); \
43+
if (helpMessage) { \
44+
helpCommand = substr($$1, 0, index($$1, ":")-1); \
45+
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
46+
printf "%-30s %s\n", helpCommand, helpMessage; \
47+
} \
48+
} \
49+
{ lastLine = $$0 }' $(MAKEFILE_LIST)

examples/vault-s3-private/README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Example showing Vault and IAM Integration
2+
3+
This example creates a private s3 bucket resources. It then uses vault
4+
to create keys which only has access to those s3 buckets. The example
5+
code will create an IAM role with access to that bucket and will also
6+
configure vault so that we can dynamically generate credentials for
7+
accessing that bucket.
8+
9+
## Requirements
10+
11+
These are the required things for this example:
12+
13+
* A running vault server. If you just want to experiment with this,
14+
run a development server using:
15+
16+
``` shellsession
17+
vault server -dev
18+
```
19+
20+
* The AWS access and secret keys for an IAM user which the AWS Secret
21+
Backend for Vault will use for issuing new credentials. If you don't
22+
have any, you can create one using [vault-iam
23+
module](../../modules/vault-iam). You need to put the access keys in
24+
[variables.tf](./variables.tf)
25+
26+
27+
## Environment creation and deployment
28+
29+
``` shellsession
30+
$ make init
31+
$ make plan
32+
$ make apply
33+
module.vault_aws_backend.vault_aws_secret_backend.aws: Creating...
34+
module.vault_aws_backend.vault_aws_secret_backend.aws: Creation complete after 0s [id=fpco/aws/dev/vault]
35+
aws_iam_role.vault_bucket_role: Creating...
36+
aws_s3_bucket.vault-test-bucket: Creating...
37+
aws_iam_role.vault_bucket_role: Still creating... [10s elapsed]
38+
aws_s3_bucket.vault-test-bucket: Still creating... [10s elapsed]
39+
aws_iam_role.vault_bucket_role: Still creating... [20s elapsed]
40+
aws_s3_bucket.vault-test-bucket: Still creating... [20s elapsed]
41+
aws_iam_role.vault_bucket_role: Creation complete after 22s [id=bucket_access_role]
42+
module.vault_aws_backend.vault_aws_secret_backend_role.aws_role: Creating...
43+
module.vault_aws_backend.vault_aws_secret_backend_role.aws_role: Creation complete after 0s [id=fpco/aws/dev/vault/roles/s3_app_user]
44+
aws_s3_bucket.vault-test-bucket: Still creating... [30s elapsed]
45+
aws_s3_bucket.vault-test-bucket: Still creating... [40s elapsed]
46+
aws_s3_bucket.vault-test-bucket: Still creating... [50s elapsed]
47+
aws_s3_bucket.vault-test-bucket: Still creating... [1m0s elapsed]
48+
aws_s3_bucket.vault-test-bucket: Still creating... [1m10s elapsed]
49+
aws_s3_bucket.vault-test-bucket: Still creating... [1m20s elapsed]
50+
aws_s3_bucket.vault-test-bucket: Still creating... [1m30s elapsed]
51+
aws_s3_bucket.vault-test-bucket: Still creating... [1m40s elapsed]
52+
aws_s3_bucket.vault-test-bucket: Still creating... [1m50s elapsed]
53+
aws_s3_bucket.vault-test-bucket: Still creating... [2m0s elapsed]
54+
aws_s3_bucket.vault-test-bucket: Still creating... [2m10s elapsed]
55+
aws_s3_bucket.vault-test-bucket: Still creating... [2m20s elapsed]
56+
aws_s3_bucket.vault-test-bucket: Still creating... [2m30s elapsed]
57+
aws_s3_bucket.vault-test-bucket: Still creating... [2m40s elapsed]
58+
aws_s3_bucket.vault-test-bucket: Creation complete after 2m48s [id=vault-fpco-test-bucket]
59+
aws_iam_role_policy.vault_bucket_policy: Creating...
60+
aws_iam_role_policy.vault_bucket_policy: Still creating... [10s elapsed]
61+
aws_iam_role_policy.vault_bucket_policy: Still creating... [20s elapsed]
62+
aws_iam_role_policy.vault_bucket_policy: Creation complete after 24s [id=bucket_access_role:bucket-policy]
63+
64+
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
65+
66+
The state of your infrastructure has been saved to the path
67+
below. This state is required to modify and destroy your
68+
infrastructure, so keep it safe. To inspect the complete state
69+
use the `terraform show` command.
70+
71+
State path: terraform.tfstate
72+
```
73+
74+
## Testing
75+
76+
Make sure you are already authorized with the vault server. If not,
77+
use `vault login` to do it. And then, you can dynamically create AWS
78+
credentials for accessing the s3 bucket you created:
79+
80+
``` shellsession
81+
$ vault read fpco/aws/dev/vault/creds/s3_app_user
82+
Key Value
83+
--- -----
84+
lease_id fpco/aws/prod/vault/creds/s3_app_user/eJcLUNbpTNRFpLoTL9mEW76p
85+
lease_duration 14m59s
86+
lease_renewable false
87+
access_key xxx
88+
secret_key xxx
89+
security_token xxx
90+
```
91+
92+
Now let's try to see all the files in our bucket:
93+
94+
``` shellsession
95+
$ env AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx aws s3 ls s3://vault-fpco-test-bucket
96+
```
97+
98+
It gives you no output since there are no files. But the command
99+
works, which confirms us that the generated credentials are working as
100+
expected.
101+
102+
Now let's try to do something for which you don't have access with the
103+
same credentials:
104+
105+
``` shellsession
106+
$ env AWS_ACCESS_KEY_ID=xxxx AWS_SECRET_ACCESS_KEY=xxxx AWS_SESSION_TOKEN=xxx aws ec2 describe-instances --region="us-east-2"
107+
An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.
108+
```
109+
110+
That doesn't work, which is expected. Let's try to see if we can
111+
access files of some other buckets which is present:
112+
113+
``` shellsession
114+
$ env AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx aws s3 ls s3://some-other-existing-bucket
115+
An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
116+
```
117+
118+
## Destruction
119+
120+
``` shellsession
121+
$ make destroy
122+
$ make clean
123+
```
124+
125+
## Notes
126+
127+
- This example was last tested with `Terraform v0.12.3`
128+
- This example assumes AWS credentials setup with access to the **us-east-2** region.

examples/vault-s3-private/main.tf

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
resource "aws_s3_bucket" "vault-test-bucket" {
2+
bucket = "vault-fpco-test-bucket"
3+
acl = "private"
4+
region = "us-east-2"
5+
6+
tags = {
7+
Name = "Vault test bucket"
8+
Environment = "Dev"
9+
}
10+
}
11+
12+
# Here we allow everyone to assume this role. In production systems
13+
# it's best to restrict it's scope so that only some IAM users are
14+
# able to assume this role.
15+
resource "aws_iam_role" "vault_bucket_role" {
16+
name = "bucket_access_role"
17+
18+
assume_role_policy = <<EOF
19+
{
20+
"Version": "2012-10-17",
21+
"Statement": [
22+
{
23+
"Action": "sts:AssumeRole",
24+
"Principal": {
25+
"AWS": "*"
26+
},
27+
"Effect": "Allow",
28+
"Sid": ""
29+
}
30+
]
31+
}
32+
EOF
33+
tags = {
34+
Environment = "Dev"
35+
}
36+
}
37+
38+
resource "aws_iam_role_policy" "vault_bucket_policy" {
39+
name = "bucket-policy"
40+
role = "${aws_iam_role.vault_bucket_role.id}"
41+
policy = <<EOF
42+
{
43+
"Version": "2012-10-17",
44+
"Statement": [
45+
{
46+
"Effect": "Allow",
47+
"Action": ["s3:*", "iam:CreateAccessKey"],
48+
"Resource": ["${aws_s3_bucket.vault-test-bucket.arn}"]
49+
}
50+
]
51+
}
52+
EOF
53+
}
54+
55+
module "vault_aws_backend" {
56+
source = "../../modules/vault-aws-backend/"
57+
vault_address = "${var.vault_address}"
58+
vault_token = "${var.vault_token}"
59+
secret_backend_path = "${var.secret_backend_path}"
60+
default_lease_ttl_seconds = "${var.default_lease_ttl_seconds}"
61+
max_lease_ttl_seconds = "${var.max_lease_ttl_seconds}"
62+
credential_type = "${var.credential_type}"
63+
role_name = "${var.role_name}"
64+
role_arn = "${aws_iam_role.vault_bucket_role.arn}"
65+
access_key = "${var.access_key}"
66+
secret_key = "${var.secret_key}"
67+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
variable "vault_address" {
2+
description = "URL for the Vault server"
3+
default = "http://127.0.0.1:8200"
4+
}
5+
variable "vault_token" {
6+
description = "Vault token needed for authorization to the server"
7+
default = "xxx"
8+
}
9+
10+
variable "region" {
11+
description = "AWS Region"
12+
type = "string"
13+
default = "us-east-2"
14+
}
15+
16+
variable "secret_backend_path" {
17+
description = "Unique AWS secret path for mouting"
18+
type = "string"
19+
default = "fpco/aws/dev/vault"
20+
}
21+
22+
variable "default_lease_ttl_seconds" {
23+
description = "The default TTL for credentials issued by this backend."
24+
type = "string"
25+
default = "900"
26+
}
27+
28+
variable "max_lease_ttl_seconds" {
29+
description = "The maximum TTL that can be requested for credentials issued by this backend."
30+
type = "string"
31+
default = "900"
32+
}
33+
34+
variable "credential_type" {
35+
description = "Specifies the type of credential to be used when retrieving credentials from the role."
36+
type = "string"
37+
default = "assumed_role"
38+
}
39+
40+
variable "access_key" {
41+
description = "The AWS Access Key ID this backend should use to issue new credentials."
42+
type = "string"
43+
default = "xxx"
44+
}
45+
46+
variable "secret_key" {
47+
description = "The AWS Secret Key this backend should use to issue new credentials."
48+
type = "string"
49+
default = "xxx"
50+
}
51+
52+
variable "role_name" {
53+
description = "The name to identify this role within the backend. Must be unique within the backend."
54+
type = "string"
55+
default = "s3_app_user"
56+
}

modules/vault-aws-backend/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# AWS Secret Backend for Vault
2+
3+
This module creates an AWS secret backend and a role for the
4+
backend. Roles are used to map credentials to the policies that
5+
generated them. For an example of it's use, [see
6+
vault-s3-private](../../examples/vault-s3-private).

modules/vault-aws-backend/main.tf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
provider "aws" {
2+
region = "${var.region}"
3+
}
4+
5+
provider "vault" {
6+
address = "${var.vault_address}"
7+
token = "${var.vault_token}"
8+
}
9+
10+
resource "vault_aws_secret_backend" "aws" {
11+
region = "${var.region}"
12+
access_key = "${var.access_key}"
13+
secret_key = "${var.secret_key}"
14+
path = "${var.secret_backend_path}"
15+
default_lease_ttl_seconds = "${var.default_lease_ttl_seconds}"
16+
max_lease_ttl_seconds = "${var.max_lease_ttl_seconds}"
17+
}
18+
19+
resource "vault_aws_secret_backend_role" "aws_role" {
20+
backend = "${vault_aws_secret_backend.aws.path}"
21+
name = "${var.role_name}"
22+
credential_type = "${var.credential_type}"
23+
role_arns = ["${var.role_arn}"]
24+
}
25+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
variable "vault_address" {
2+
description = "URL for the Vault server"
3+
type = "string"
4+
}
5+
6+
variable "vault_token" {
7+
description = "Vault token needed for authorization to the server"
8+
type = "string"
9+
}
10+
11+
variable "region" {
12+
description = "AWS Region"
13+
type = "string"
14+
default = "us-east-2"
15+
}
16+
17+
variable "secret_backend_path" {
18+
description = "Unique AWS secret path for mouting"
19+
type = "string"
20+
}
21+
22+
variable "default_lease_ttl_seconds" {
23+
description = "The default TTL for credentials issued by this backend."
24+
type = "string"
25+
}
26+
27+
variable "max_lease_ttl_seconds" {
28+
description = "The maximum TTL that can be requested for credentials issued by this backend."
29+
type = "string"
30+
}
31+
32+
variable "credential_type" {
33+
description = "Specifies the type of credential to be used when retrieving credentials from the role."
34+
type = "string"
35+
}
36+
37+
variable "access_key" {
38+
description = "The AWS Access Key ID this backend should use to issue new credentials."
39+
type = "string"
40+
}
41+
42+
variable "secret_key" {
43+
description = "The AWS Secret Key this backend should use to issue new credentials."
44+
type = "string"
45+
}
46+
47+
variable "role_name" {
48+
description = "The name to identify this role within the backend. Must be unique within the backend."
49+
type = "string"
50+
}
51+
52+
variable "role_arn" {
53+
description = "Specifies the ARN of the AWS role this Vault role is allowed to assume"
54+
type = "string"
55+
}

0 commit comments

Comments
 (0)