Passwörter. Ein Quell der Freude, gerade beim Thema Infrastructure as Code (in meinem Fall mittels terraform)
Ich arbeite im Moment an einem neuen Projekt in der Arbeit in der ich 4 identische Umgebungen in AWS aufbauen darf und natürlich werden dort diverse Systeme angebunden welche sich mittels Authentifizierung unterhalten.
Vorher sah meine Codebase ungefähr so aus. Credentials wo man hinsah.
module "mysql_db" {
source = "../../modules/rds"
name = "${var.environment}-mysql"
subnet_ids = module.dcc_vpc.private_subnet_ids
tags = var.tags
vpc_id = module.dcc_vpc.vpc_id
password = "kommtnieeinerdrauf42"
}
module "container" {
source = "github.com/cloudposse/terraform-aws-ecs-container-definition"
[...]
repository_credentials = {
username = "foo"
password = "garantiertsicher23"
}
}
module "ecs_task" {
app_port = 8080
app_env = [
{
name = "DB_PASSWORD"
value = "liebernichtinsrepocomitten1234"
}
]
Natürlich bin ich nicht der Einzige mit solchen Problemen. Es gab dann mehrere Optionen wie ich damit umgehe.
- Ignorieren (wie in anderen Projekten)
- Alles in Umgebungsvariablen auslagern
- Hashicorp Vault
- Secrets Provider
- AWS Secrets Manager
Ich habe mich dann für Letzteres entschieden. Vorrangig aus Neugier und Bequemlichkeit. Mein Cloud Provider stellt mir ein Tool zur Verfügung und mein Tooling unterstützt es. Also warum nicht.
Zuerst muss ich mich dann im Webinterface der AWS anmelden und die Credentials hinterlegen.
und danach aus der Übersicht die ARN
heraussuchen. Diese wird danach wieder
bei der Anbindung über einen Data Provider
in terraform
benötigt.
Das fühlt sich am Anfang irgendwie falsch an, aber wenn man bedenkt das die
Credentials gerade deshalb nicht im Repo verwaltet werden, damit man sie eben
nicht im Repo hat gleicht das das dreckige Gefühl aus manuelle ARN
s in den
Code zu pasten.
Im data.tf
File der jeweiligen Umgebung kann ich mir die Resourcen jetzt
zum Weiterverarbeiten abholen:
data "aws_secretsmanager_secret" "db" {
arn = "arn:aws:secretsmanager:eu-central-1:xxx"
}
data "aws_secretsmanager_secret_version" "db" {
secret_id = data.aws_secretsmanager_secret.db.id
}
Wenn ich dann die Secrets im Code brauche, rufe ich sie über
data.aws_secretsmanager_secret_version
ab.
module "mysql_db" {
source = "../../modules/rds"
name = "${var.environment}-mysql"
subnet_ids = module.dcc_vpc.private_subnet_ids
tags = var.tags
vpc_id = module.dcc_vpc.vpc_id
password = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["password"]
}
module "container" {
source = "github.com/cloudposse/terraform-aws-ecs-container-definition"
[...]
repository_credentials = jsondecode(data.aws_secretsmanager_secret_version.repo.secret_string)
}
So nutze ich nun neben ALB, ECS, Fargate, RDS & Cloudwatch eben noch einen weiteren AWS Service: Secrets Manager.
Alle anderen Optionen (siehe oben) gehen natürlich auch. Na gut, vielleicht
bis auf die Erste. Ich hatte allerdings keine Lust eine Vault Instanz selbst
zu betreiben, auch wenn Vault die am Besten unterstützte Lösung gewesen wäre.
Die Umgebungsvariablen fielen deswegen aus weil wir terraform
mittels
Bamboo CI/CD im Prozess benutzen und dann dort die Credentials überall
verteilt wären.
Ich denke meine nächste Wahl wäre der Secrets Provider gewesen, da die Credentials hier nur 1x in das Statefile importiert werden müssen und dann für immer dort bestehen bleiben und auch auf Build Agents als auch auf den Rechnern der Kollegen verfügbar wären. Mit dem AWS Service hatte ich mich dann aber besser gefühlt.