Blog

AWS Secure Shell (SSH) Einrichtung mit EC2 und CloudFormation

Dennis Vriend

Aktualisiert Oktober 21, 2025
5 Minuten

Bei binx.io schaffen wir unveränderliche Infrastrukturen. Mit Hilfe der Automatisierung und der gewünschten Statuskonfiguration nutzen wir CloudFormation für die Erstellung der Infrastruktur. Es ist jedoch nicht möglich, mit CloudFormation Amazon EC2-Instanzen zu erstellen, die mit einem Public/Private Key-Paar bereitgestellt werden. Aus diesem Grund hat Mark van Holsteijn, CTO von binx.io, den binxio/cfn-secret-provider entwickelt. In dem Blog Deploying private key pairs with AWS CloudFormation stellt Mark den secret provider und verschiedene Anwendungsfälle vor. Der secret provider ist eine benutzerdefinierte CloudFormation-Ressource, die RSA-Schlüssel und KeyPairs erstellt, die zur Erzeugung von Geheimnissen verwendet werden können. In diesem Blog sehen wir uns eine Verwendung des Secret Providers an, nämlich die Erzeugung eines öffentlichen/privaten Schlüsselpaars und dessen Verwendung zur Bereitstellung einer EC2.

RSA und SSH

RSA-Schlüssel werden bei der Verschlüsselung mit öffentlichen Schlüsseln verwendet. Der Algorithmus verwendet einen privaten Schlüssel und einen abgeleiteten öffentlichen Schlüssel. Der private Schlüssel sollte geheim gehalten werden, aber der öffentliche Schlüssel kann mit anderen geteilt werden. RSA-Schlüssel werden bei der Einrichtung von Secure Shell oder 'SSH' verwendet. Bei Secure Shell wird der öffentliche Schlüssel auf dem Server gespeichert, um einen Client zu identifizieren. Denn bei RSA gibt es eine Eins-zu-Eins-Beziehung zwischen dem öffentlichen und dem privaten Schlüssel. Der Grund dafür ist, dass die öffentlichen Schlüssel von einem einzigen privaten Schlüssel abgeleitet werden. Der private Schlüssel wird vom Client verwendet, um sich beim Server anzumelden. Die Verbindung mit dem Server wird vom Client initiiert. Der Client verschlüsselt die SSH-Verbindung mit dem privaten Schlüssel. Der Server kann die Verbindung mit dem öffentlichen Schlüssel entschlüsseln. Die Sicherheit ist einfach: Nur der öffentliche Schlüssel kann eine mit dem privaten Schlüssel initiierte Verbindung entschlüsseln. Wenn die Entschlüsselung erfolgreich ist, weiß der Server automatisch, dass die Verbindung vertrauenswürdig ist.

Geheimnisse generieren

Der Secret Provider kann RSA-Schlüssel generieren. Der private Schlüssel wird im AWS-Parameterspeicher gespeichert. Der öffentliche Schlüssel ist verfügbar, wenn Sie den benutzerdefinierten Anbieter fragen. Ich habe den öffentlichen Schlüssel mit einer CloudFormation-Ausgabe exportiert. Der geheime Anbieter kann die RSA-Schlüssel auch als EC2 KeyPair speichern. Unten sehen Sie, wie Sie eine solche Konfiguration einrichten.

  PrivateKey:
    Type: Custom::RSAKey
    Properties:
      Name: /bastion/default/private-key
      RefreshOnUpdate: false
      ServiceToken: !GetAtt CFNSecretProvider.Arn

  KeyPair:
    Type: Custom::KeyPair
    DependsOn: PrivateKey
    Properties:
      Name: BastionKeyPair
      PublicKeyMaterial: !GetAtt 'PrivateKey.PublicKey'
      ServiceToken: !GetAtt CFNSecretProvider.Arn

Der geheime Anbieter ist eine benutzerdefinierte Ressource von CloudFormation. Die Implementierung ist ein Lambda und muss in Ihrer AWS-Umgebung bereitgestellt werden.

  CFNSecretProvider:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Sub 'binxio-public-${AWS::Region}'
        S3Key: lambdas/cfn-secret-provider-0.13.2.zip
      Handler: secrets.handler
      MemorySize: 128
      Role: !GetAtt 'CFNSecretProviderRole.Arn'
      Runtime: python3.6
      Timeout: 300

  CFNSecretProviderLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub '/aws/lambda/${CFNSecretProvider}'
      RetentionInDays: 30

Das Lambda braucht die entsprechenden Berechtigungen, um die Schlüssel zu erzeugen und zu speichern.

  CFNSecretProviderRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
          Condition: {}
      Path: /
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
      - PolicyName: CFNCustomSecretProviderPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - iam:CreateAccessKey
            - iam:UpdateAccessKey
            - iam:DeleteAccessKey
            - ssm:PutParameter
            - ssm:GetParameter
            - ssm:DeleteParameter
            - ec2:ImportKeyPair
            - ec2:DeleteKeyPair
            Resource:
            - '*'
          - Effect: Allow
            Action:
            - kms:Encrypt
            - kms:Decrypt
            Resource:
            - '*'

Eine EC2-Instanz kann mit dem KeyPair konfiguriert werden, das vom benutzerdefinierten Anbieter erstellt wurde.

  BastionHost:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap ['NatAMI', 'eu-west-1', 'ami']
      KeyName: BastionKeyPair
      InstanceType: 't3.micro'
      SourceDestCheck: false
      SubnetId: !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref BastionHostSecurityGroup
      IamInstanceProfile: !Ref BastionInstanceProfile
      BlockDeviceMappings:
        - DeviceName: /dev/xvdcz
          Ebs:
            VolumeType: gp2
            VolumeSize: 10
            DeleteOnTermination: true
            Encrypted: true
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          export AWS_DEFAULT_REGION=eu-west-1
          yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm

  BastionInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref BastionRole

  BastionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM'
        - 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser'
      Policies:
        - PolicyName: gitlab-runner
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - ssm:GetParameter
                Resource:
                  - !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/bastion/default/*'

  BastionHostSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      Groupcontent: 'Security group for the bastion host'
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: '-1'
          CidrIp: '0.0.0.0/0'
      SecurityGroupEgress:
        - IpProtocol: '-1'
          CidrIp: '0.0.0.0/0'

Zugriff auf den privaten Schlüssel

Der private Schlüssel kann mit Hilfe der AWS CLI heruntergeladen werden. Sie benötigen den privaten Schlüssel, um eine SSH-Verbindung von Ihrem Computer zur EC2-Instanz zu initiieren.

# print the private key
aws ssm get-parameter --name /bastion/default/private-key --with-decryption | jq -r '.Parameter.Value'
# copy the private key to the clipboard
aws ssm get-parameter --name /bastion/default/private-key --with-decryption | jq -r '.Parameter.Value' | pbcopy
# writing the private key to 'bastion.pem'
aws ssm get-parameter --name /bastion/default/private-key --with-decryption | jq -r '.Parameter.Value' > bastion.pem

SSH einrichten

Um eine SSH-Verbindung aufzubauen, benötigen Sie Zugriff auf den privaten Schlüssel. Die Datei mit dem privaten Schlüssel benötigt die Berechtigung 0600. Geben Sie zum Anmelden make create && make ssh oder ein:

DNSNAME=`sceptre --output json describe-stack-outputs example vpc | jq -r '.[] | select(.OutputKey=="BastionHostPublicDnsName") | .OutputValue'`
ssh -i bastion.pem ec2-user@$DNSNAME

Beispiel

Das Beispielprojekt zeigt, wie Sie ein Projekt zur Erstellung von KeyPairs konfigurieren und wie Sie eine EC2-Instanz mit einem KeyPair mit CloudFormation konfigurieren. Das Beispiel kann mit bereitgestellt und mit entfernt werden. Zur Anmeldung geben Sie make ssh ein.

Fazit

Mit dem binxio/cfn-secret-provider ist es möglich, mit AWS CloudFormation Geheimnisse zu erzeugen. In diesem Blog haben wir gesehen, wie RSA-Schlüssel erstellt werden, wie EC2-Schlüsselpaare erstellt werden und wie eine EC2-Instanz für die Verwendung dieses Schlüsselpaars konfiguriert wird. Wir haben auch gesehen, wie Sie Zugriff auf den privaten Schlüssel erhalten und wie Sie diesen Schlüssel verwenden, um eine SSH-Verbindung mit der EC2-Instanz herzustellen.

Verfasst von

Dennis Vriend

Contact

Let’s discuss how we can support your journey.