A module to create application secrets stored in AWS Secrets Manager.
- Terraform (version
1.0.0or higher) - AWS provider (version
2.60or 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://git@github.com/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://git@github.com/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_arnoutput. -
In the
account_id2AWS account, create the roleroleNameand 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-roleto create a new role. In your case, you may want to attach the newly created policy to an existing role.
- In the
account_id3AWS account, create the useruser-nameand 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-userto 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=mainin 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
ReleaseGithub workflow - Click
Run workflowdropdown in the top right corner of the table listing the workflow runs - Choose the
mainbranch and clickRun workflowbutton 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.