Es gibt viele Möglichkeiten, 'Geheimnisse' in ECS und ECS Fargate zu verwenden. Meistens werden sie mit Hilfe von Umgebungsvariablen offengelegt, da dies vor einigen Jahren die einzige einfache Möglichkeit war. Heute haben wir zwei verbesserte Optionen. Sie können ein Tool zu Ihrem Docker-Container hinzufügen, das Ihre Geheimnisse abruft und entschlüsselt, bevor Sie sie an die Anwendung weitergeben. Die andere Möglichkeit besteht darin, das Abrufen und Entschlüsseln in die Anwendung einzubetten. Beide Ansätze werden in diesem Blogbeitrag behandelt. So werden wir vorgehen:
- Legen Sie ein Geheimnis in den SSM-Parameterspeicher
- Fügen Sie das Tool ssm-env zu Ihrem Dockerfile hinzu, um die Geheimnisse beim 'Booten' zu ersetzen
- Fügen Sie Ihrer Anwendung eine Logik zum Abrufen von Geheimnissen hinzu
- Hinzufügen eines Verweises auf das Geheimnis in Container-Umgebungsvariablen mit CloudFormation
1. Legen Sie ein Geheimnis im SSM Parameter Store ab
Diesmal fügen wir das Geheimnis manuell hinzu, z. B. im Falle eines mit Ihnen geteilten Api-Schlüssels eines Dritten. Sie können auch mit der
aws ssm put-parameter
--name my.little.secret
--type SecureString
--value "th15-1s-53cur3"
2. Fügen Sie das Tool ssm-env zu Ihrer Anwendung hinzu
Fügen Sie nun den folgenden Code zu Ihrer Dockerdatei hinzu. Er wird das in Golang geschriebene Tool ssm-env herunterladen und validieren. Um auf die AWS-APIs wie SSM zuzugreifen, müssen Sie Zertifikate installieren. Das vollständige Dockerfile finden Sie hier.
FROM alpine
# SSM Secret Sauce
RUN wget -O /usr/local/bin/ssm-env https://github.com/remind101/ssm-env/releases/download/v0.0.3/ssm-env
RUN echo "c944fc169d860a1079e90b03a8ea2c71f749e1265e3c5b66f57b2dc6e0ef84f8 /usr/local/bin/ssm-env" | sha256sum -c -
RUN chmod +x /usr/local/bin/ssm-env
RUN apk add —no-cache ca-certificates
ENTRYPOINT ["/usr/local/bin/ssm-env", "-with-decryption"]
# /SSM Secret Sauce
Es durchläuft alle Umgebungsvariablen und sucht nach dem Präfix ssm://. Wenn es gefunden wird, verwendet es die IAM-Rolle des Containers, um das Geheimnis abzurufen und ersetzt den Wert für das Geheimnis. Zum Beispiel:
MY_LITTLE_SECRET=ssm://my.secret
# becomes within the container
MY_LITTLE_SECRET=th15-1s-53cur3
3. Fügen Sie Ihrer Anwendung eine Logik zum Abrufen von Geheimnissen hinzu
In diesem Beispiel wird das öffentliche Docker-Image: mvandongen/alittlesecret verwendet, bei dem es sich lediglich um eine sehr einfache Python-Flask-Anwendung handelt. Im ersten Abschnitt wird das SSM-Geheimnis mithilfe des SDK abgerufen. Das Geheimnis im zweiten Teil ist bereits entschlüsselt. Dies wird wahrscheinlich für (Alt-)Anwendungen oder Anwendungen verwendet, die Sie nicht einfach ändern können.
from flask import Flask
import boto3
import os
app = Flask(__name__)
def ssm_secret(path, prefix = "ssm_sdk://"):
client = boto3.client('ssm') # uses the container role
prefix_len = len(prefix)
if os.environ['SECRET_SDK'][0:prefix_len] == prefix:
result = client.get_parameter(
Name=os.environ['SECRET_SDK'][prefix_len:],
WithDecryption=True
)
secret = result['Parameter']['Value']
else:
secret = os.environ['SECRET_SDK']
return secret
@app.route("/")
def hello():
# section 1: get the secret and decrypt it using the sdk
secret = ssm_secret(
os.environ['SECRET_SDK'],
os.environ['SECRET_SDK_PREFIX']
)
section1 = "SDK decrypted: " + secret
# section 2: get the already decrypted secret
section2 = "ssn-env decrypted: " + os.environ['SECRET']
return section1 + section2
app.run(host='0.0.0.0', port=80)
4. Fügen Sie in den Container-Umgebungsvariablen mit CloudFormation einen Verweis auf das Geheimnis hinzu
Lassen Sie uns diesen Fargate-Container mit CloudFormation bereitstellen. Er funktioniert in jeder öffentlichen VPC, auch in der Standard-VPC.
AWSTemplateFormatVersion: "2010-09-09"
Description: >
"AWS Example Setup For Secrets in ECS / ECS Fargate"
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: >
"ID of the VPC to deploy the containers to."
Subnets:
Type: List<AWS::EC2::Subnet::Id>
Description: >
"IDs of the Subnets to deploy the containers to."
Resources:
Cluster:
Type: AWS::ECS::Cluster
Properties: {}
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
TaskDefinition: !Ref 'TaskDefinition'
DesiredCount: 1
LaunchType: 'FARGATE'
NetworkConfiguration:
AwsvpcConfiguration:
Subnets: !Ref 'Subnets'
SecurityGroups:
- !Ref SecurityGroup
AssignPublicIp: 'ENABLED'
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
NetworkMode: 'awsvpc'
Cpu: '256'
Memory: '512'
ExecutionRoleArn: !Ref TaskRole
TaskRoleArn: !Ref TaskRole
RequiresCompatibilities:
- FARGATE
ContainerDefinitions:
-
Name: "asecretservice"
Image: "mvandongen/asecretservice:latest"
PortMappings:
- ContainerPort: 80
Environment:
- Name: "SECRET"
Value: "ssm://my.little.secret"
- Name: "SECRET_SDK"
Value: "ssm_sdk://my.little.secret"
- Name: "SECRET_SDK_PREFIX"
Value: "ssm_sdk://"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref AWS::Region
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: ecs
TaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess'
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref 'VpcId'
GroupDescription: "Public access to container"
SecurityGroupIngress:
- FromPort: 80
ToPort: 80
IpProtocol: 'tcp'
CidrIp: "0.0.0.0/0"
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "${AWS::StackName}"
Aufgrund der wenigen Parameter, die leicht auszuwählen sind, setzen wir den Stack über die Konsole ein. Wenn Sie möchten, können Sie auch den Cli verwenden. 
Suchen Sie nun die öffentliche IP-Adresse des Docker-Containers, der in Fargate läuft, und verwenden Sie curl oder einen Webbrowser, um die entschlüsselten Geheimnisse zu überprüfen. Versuchen Sie auch, die Geheimnisse in der AWS Management Console zu finden. Sie sind nicht in der CloudFormation-Konsole und nicht in der ECS Fargate-Konsole sichtbar. Sie sind nur im SSM Parameter Store sichtbar.
Fazit
In diesem Blogbeitrag haben wir ein Geheimnis im AWS SSM-Parameterspeicher erstellt und es in einem Docker-Container abgerufen, ohne es irgendwo in der Verwaltungskonsole offenzulegen. Durch die Verwendung des SDK stellt der Programmierer sicher, dass das Geheimnis nur dort abgerufen und verwendet wird, wo es benötigt wird. Das ist am sichersten.
Im zweiten Beispiel handelt es sich aus Sicht der Anwendung lediglich um eine Umgebungsvariable innerhalb des Containers. Wenn Sie alle Umgebungsvariablen preisgeben, geben Sie auch Ihr Geheimnis preis, was es weniger sicher macht.
Jetzt wird es wirklich einfach, Geheimnisse zu rotieren. Dazu ist nicht einmal eine Bereitstellung erforderlich.
- Aktualisieren Sie das Geheimnis im SSM-Parameterspeicher
- Beenden Sie Container auf elegante Weise
- Neue Container mit neuen Geheimnissen werden wiederhergestellt
Wenn Sie so weit gekommen sind, sind Sie vielleicht auch daran interessiert, Geheimnisse in CloudFormation sicher zu verteilen oder zu speichern.
Verfasst von
Martijn van Dongen
Unsere Ideen
Weitere Blogs
Contact




