This small binary fetches JSON formatted secrets from AWS Secrets Manager.
It passes the fetched secrets to the binary (that requires the secrets) when it is executed. (see execve)
The secrets should be stored in a AWS Secrets Manager secret with a value specified in a flat JSON K:V format.
The Secrets Manager secret name should usually follow the path pattern $service_name/$env/secrets.
fetch-secrets will use the IAM role tags to auto-discover the secrets to be fetched.
Any tag keys prefixed with secrets_ will be matched; the corresponding tag value be a Secrets Manager secret name.
eg; The tag secrets_default = myservice/dev/secrets will load the secrets stored in the secret named myservice/dev/secrets.
You can specify multiple tags, however, the merging order is arbitrary so don't expect precedence.
fetch-secrets supports the use of an FS_REGION env var, which can be configured when applications use different regions
for their secrets. Note, the application will still use AWS_REGION as normal.
./fetch-secrets mycommand subcommand --my-arg exampleThis will load the variables and exec mycommand (with the subcommand and args), making the secret values available as env vars for the mycommand application.
To run fetch-secrets in a docker container, download the latest binary release, update the binary permissions and prepend to your existing app command. eg;
ADD https://github.com/slicelife/fetch-secrets/releases/download/v0.2.0/fetch-secrets-v0.2.0-linux-amd64 /fetch-secrets
RUN chmod +x /fetch-secrets
CMD ["/fetch-secrets", "/entrypoint.sh"]In order to auto-discover secrets, fetch-secrets or the container/pod/instance it is running on requires the following IAM policy:
resource "aws_iam_policy" "service" {
name = local.role_name
policy = data.aws_iam_policy_document.service.json
}
data "aws_iam_policy_document" "service" {
statement {
actions = ["secretsmanager:GetSecretValue"]
resources = [
"arn:aws:secretsmanager:*:${data.aws_caller_identity.current.account_id}:secret:${var.service_name}/${var.short_env}/*"
]
effect = "Allow"
}
statement {
actions = ["iam:ListRoleTags"]
resources = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${local.role_name}"]
effect = "Allow"
}
statement {
actions = ["sts:GetCallerIdentity"]
resources = ["*"]
effect = "Allow"
}
}Or alternatively using embedded JSON:
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : "secretsmanager:GetSecretValue",
"Resource" : [
"arn:aws:secretsmanager:*:${data.aws_caller_identity.current.account_id}:secret:${var.service_name}/${var.short_env}/*"
]
},
{
"Effect" : "Allow",
"Action" : "iam:ListRoleTags",
"Resource" : [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${local.role_name}"
]
},
{
"Effect" : "Allow",
"Action" : "sts:GetCallerIdentity",
"Resource" : ["*"]
}
]
})You can add tags to your role using Terraform. eg;
tags = {
secrets_default = "${var.service_name}/${var.short_env}/secrets"
}Build the binary using:
make artifactThe resulting binary will be called fetch-secrets.
NOTE: If you need to compile a linux specific binary run and you're on a Mac use:
GOOS=linux go buildTest the code using:
make testLint the code using:
make lintGenerate mocks for unit testing:
make generatefetch-secrets uses JSON logging throughout. The logging should indicate, the role determined, the tag keys and values as well as the secret-names to fetch values for.
If logs are unavailable, the following exit-codes should be helpful in indicating where the issue might be:
| Exit Code | Description |
|---|---|
| 1 | Executable to run not found |
| 2 | Problem loading AWS config |
| 3 | Failed to get AWS role, tags or secrets |
| 4 | Timeout (default 1min) |
| 5 | Failed to run executable |