A module to create application secrets stored in AWS Secrets Manager.
- Terraform (version
1.0.0
or higher) - AWS provider (version
2.60
or higher)
This is a main use-case of the module. When you want to create application secrets that are not intended to be shared with other AWS accounts please refer to the following example:
module "secrets" {
source = "git::ssh://[email protected]/scribd/terraform-aws-app-secrets.git?ref=main"
app_name = "project"
secrets = [
{
name = "app-env"
value = "development"
allowed_arns = []
},
{
name = "app-database-host"
value = "[value required]"
allowed_arn = []
},
{
name = "app-database-port"
value = "3306"
allowed_arns = []
}
]
tags = {
department = "engineering"
project = "project"
env = "development"
}
}
The module allows you to delegate read-only access to your secrets to other AWS accounts. Unfortunately, the configuration can't be fully provisioned by the module. It requires additional configuration in the AWS accounts where the secrets are requested from. Below you can find an example of sharing secrets with 2 different AWS accounts.
- Create secrets within an AWS account (in the example, we refer to it as
account_id1
) and specify AWS account ids or user ARNs that should have access to the secrets. The module generates resource-based policies which are attached to a secret (one policy per secret):
module "secrets" {
source = "git::ssh://[email protected]/scribd/terraform-aws-app-secrets.git?ref=main"
app_name = "project"
secrets = [
{
name = "app-env"
value = "development"
allowed_arns = []
},
{
name = "app-database-host"
value = "[value required]"
allowed_arns = [var.account_id2]
},
{
name = "app-database-port"
value = "3306"
allowed_arns = [
var.account_id2,
"arn:aws:iam::${var.account_id3}:user/user-name",
]
}
]
tags = {
department = "engineering"
project = "project"
env = "development"
}
}
The example above creates the secrets and grants access to the app-database-host
secret to the account_id2
AWS account. Access to the app-database-port
secret is granted to the account_id2
account and the user-name
user defined in the account_id3
AWS account. The app-env
secret is not shared with any other AWS accounts.
-
Run the terraform pipeline to provision the secrets and copy the KMS key ARN from the
module.secrets.kms_key_arn
output. -
In the
account_id2
AWS account, create the roleroleName
and attach a policy to it:
data "aws_iam_policy_document" "secret_access" {
statement {
actions = [
"kms:Decrypt",
"kms:DescribeKey",
]
resources = ["kms-key-arn-copied-from-step-2"]
}
statement {
actions = ["secretsmanager:GetSecretValue"]
resources = [
"arn:aws:secretsmanager:${var.aws_region}:${var.account_id1}:secret:project-app-database-host*",
"arn:aws:secretsmanager:${var.aws_region}:${var.account_id1}:secret:project-app-database-port*",
]
}
}
resource "aws_iam_policy" "secret_access" {
name_prefix = "project"
description = "Policy to access secrets for application project"
policy = data.aws_iam_policy_document.secret_access.json
}
module "iam_assumable_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
version = "~> 4.8"
create_role = true
role_name = "roleName"
role_requires_mfa = false
custom_role_policy_arns = [aws_iam_policy.secret_access.arn]
number_of_custom_role_policy_arns = 1
tags = {
department = "engineering"
project = "project"
env = "development"
}
}
Now you should be able to assume the role from within account_id2
and read the secret value.
⚠️ Note: As an example, we use a third-party moduleiam-assumable-role
to create a new role. In your case, you may want to attach the newly created policy to an existing role.
- In the
account_id3
AWS account, create the useruser-name
and attach a policy to it:
data "aws_iam_policy_document" "secret_access" {
statement {
actions = [
"kms:Decrypt",
"kms:DescribeKey",
]
resources = ["kms-key-arn-copied-from-step-2"]
}
statement {
actions = ["secretsmanager:GetSecretValue"]
resources = ["arn:aws:secretsmanager:${var.aws_region}:${var.account_id1}:secret:project-app-database-port*"]
}
}
resource "aws_iam_policy" "secret_access" {
name_prefix = "project"
description = "Policy to access secrets for application project"
policy = data.aws_iam_policy_document.secret_access.json
}
resource "aws_iam_user_policy_attachment" "user" {
user = module.user.iam_user_name
policy_arn = aws_iam_policy.secret_access.arn
}
module "user" {
source = "terraform-aws-modules/iam/aws//modules/iam-user"
version = "~> 4.8"
name = "user-name"
create_user = true
create_iam_user_login_profile = false
tags = {
department = "engineering"
project = "project"
env = "development"
}
}
⚠️ Note: As an example, we use a third-party moduleiam-user
to create a new user. In your case, you may want to attach the newly created policy to an existing user.
⚠️ IMPORTANT NOTES
- Please don't use
ref=main
in your production code. Please refer to a release tag explicitly.- Please don't put actual secret values to the terraform code except for the static configuration values (for instance, the static ports). Use any dummy values to provision the secrets. The actual values have to be set manually via AWS Web Console or AWS CLI afterwards.
Name | Description | Type | Default | Required |
---|---|---|---|---|
app_name |
Application name | string | null |
yes |
aws_region |
AWS region | string | us-east-2 |
no |
secrets |
List of objects of secrets | list(object) | null |
yes |
delete_in |
Number of days to wait before secret deletion | number | 30 |
no |
tags |
Key-value map of tags | map(string) | {} |
no |
Name | Description | Type | Default |
---|---|---|---|
name |
Secret name | string | null |
value |
Secret value | string | null |
allowed_arns |
List of principal ARNs that have access to the secret | list | null |
Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be 0
to force deletion without recovery or range from 7
to 30
days. The default value is 30
.
Name | Description | Sensitive |
---|---|---|
all |
Map of names and arns of created secrets | yes |
kms_key_arn |
The master key ARN | no |
kms_alias_arn |
The master key alias ARN | no |
This project is using semantic-release
and conventional-commits,
with the angular
preset.
Releases are done from the origin/main
branch using a manual step at the end of the CI/CD pipeline.
In order to create a new release:
- Merge / push changes to
origin/main
- Open the
Release
Github workflow - Click
Run workflow
dropdown in the top right corner of the table listing the workflow runs - Choose the
main
branch and clickRun workflow
button to start the process
A version bump will happen automatically and the type of version bump (patch, minor, major) depends on the commits introduced since the last release.
The semantic-release
configuration is in .releaserc.yml
.
Made with ❤️ by the Service Foundations team.