简体   繁体   English

Cloudformation 堆栈默认参数 SSM 参数存储

[英]Cloudformation stack default parameter SSM Parameter store

I am trying to launch a jupyterlab instance using cloudformation (its something I do a lot and sagemaker does not have a 1y free tier) so the beginning looks like this which does not work.我正在尝试使用 cloudformation 启动一个 jupyterlab 实例(这是我经常做的事情,sagemaker 没有 1y 免费层)所以一开始看起来像这样不起作用。 Specifically the password parameter特别是密码参数

# AWSTemplateFormatVersion: "2010-09-09"
Description: Creates a Jupyter Lab Instance with an Elastic Load Balancer


Parameters:
  KeyName:
    Description: >-
      Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: Must be the name of an existing EC2 KeyPair.
    Default: eduinstance
  VPC:
    Description: VPC ID of the VPC in which to deploy this stack.
    Type: AWS::EC2::VPC::Id
    ConstraintDescription: Must be the name of a valid VPC
    Default: vpc-10a7ac6a
  Subnets:
    Type: List<AWS::EC2::Subnet::Id>
    Default: subnet-8cde25d3,subnet-531fda72,subnet-4bbe3006
    Description: >-
      Subnets for the Elastic Load Balancer.
      Please include at least two subnets
  Password: 
    Type: String
    NoEcho: false
    MinLength: 4
    Default: '{{resolve:ssm:JLabPassword:1}}'
    Description: Password to set for Jupyter Lab
  EBSVolumeSize:
    Type: Number
    Description: EBS Volume Size (in GiB) for the instance
    Default: 8
    MinValue: 8
    MaxValue: 64000
    ConstraintDescription: Please enter a value between 8 GB and 64 TB
  EC2InstanceType:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - c5.large
      - m5.large
    Description: Enter t2.micro, c5.large or m5.large. Default is t2.micro.


Conditions:
  JupyterPasswordDefault: !Equals
    - !Ref Password
    - DEFAULT

Resources:
  ALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties: 
      IpAddressType: ipv4
      Scheme: internet-facing
      SecurityGroups: 
        - !GetAtt [ALBSG, GroupId]
      Subnets: !Ref Subnets
      Type: application
  
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions: 
        - Type: forward
          TargetGroupArn: !Ref ALBTargetGroup
      LoadBalancerArn: !Ref ALB
      Port: 80
      Protocol: HTTP
  
  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Port: 8888
      Protocol: HTTP
      Targets: 
        - Id: !Ref ComputeInstance
      TargetType: instance
      VpcId: !Ref VPC
  
  ComputeInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref ComputeIAMRole

  
  ComputeInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SubnetId: !Select [0, !Ref Subnets]
      KeyName: !Ref KeyName
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2:33}}'
      SecurityGroupIds: 
        - !GetAtt [ComputeSG, GroupId]
      IamInstanceProfile: !Ref ComputeInstanceProfile
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: gp2
            VolumeSize: !Ref EBSVolumeSize
            DeleteOnTermination: true
      UserData:
        Fn::Base64: !Sub
          - |
            #!/bin/bash
            yum update -y
            yum install python3-pip -y
            yum install java-1.8.0-openjdk -y
            cd /home/ec2-user/
            wget https://repo.anaconda.com/archive/Anaconda3-2020.11-Linux-x86_64.sh
            sudo -u ec2-user bash Anaconda3-2020.11-Linux-x86_64.sh -b -p /home/ec2-user/anaconda
            echo "PATH=/home/ec2-user/anaconda/bin:$PATH" >> /etc/environment
            source /etc/environment
            jupyter notebook --generate-config
            mkdir .jupyter
            cp /root/.jupyter/jupyter_notebook_config.py /home/ec2-user/.jupyter/
            echo "c = get_config()" >> .jupyter/jupyter_notebook_config.py
            echo "c.NotebookApp.ip = '*'" >> .jupyter/jupyter_notebook_config.py
            NB_PASSWORD=$(python3 -c "from notebook.auth import passwd; print(passwd('${password}'))")
            echo "c.NotebookApp.password = u'$NB_PASSWORD'" >> .jupyter/jupyter_notebook_config.py
            rm Anaconda3-2020.11-Linux-x86_64.sh
            mkdir Notebooks
            chmod 777 -R Notebooks .jupyter
            su -c "jupyter lab" -s /bin/sh ec2-user
          - password: !Ref Password #!If [JupyterPasswordDefault, '{{resolve:ssm:JupyterLabPassword:1}}', !Ref Password]

  
  ALBSG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: Security Group for JupyterLab ALB. Created Automatically.
      SecurityGroupIngress: 
        - CidrIp: 0.0.0.0/0
          Description: Allows HTTP Traffic from anywhere
          FromPort: 80
          ToPort: 80
          IpProtocol: tcp

  ComputeSG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: Security Group for JupyterLab EC2 Instance. Created Automatically.
      SecurityGroupIngress: 
        - Description: Allows JupyterLab Server Traffic from ALB.
          FromPort: 8888
          IpProtocol: tcp
          SourceSecurityGroupId: !GetAtt [ALBSG, GroupId]
          ToPort: 8890
        - CidrIp: 0.0.0.0/0
          Description: Allows SSH Access from Anywhere
          FromPort: 22
          ToPort: 22
          IpProtocol: tcp
  
  ComputeIAMRole:
    Type: AWS::IAM::Role
    Properties: 
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Description: Allows EC2 Access to S3. Created Automatically.
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess

Outputs:
  URL:
    Description: URL of the ALB
    Value: !Join 
      - ''
      - - 'http://'
        - !GetAtt 
          - ALB
          - DNSName
  
  ConnectionString:
    Description: Connection String For SSH On EC2
    Value: !Join
      - ''
      - - 'ssh -i "'
        - !Ref KeyName
        - '.pem" ec2-user@'
        - !GetAtt
          - ComputeInstance
          - PublicDnsName

It however interprets the string literally so I don't actually get my password but the resolve... itself.然而,它从字面上解释字符串,所以我实际上并没有得到我的密码,而是解析......本身。

实际参数截图

Based on the comments and new, updated template by OP, and to expand on @DennisTraub answer.基于 OP 的评论和新的更新模板,并扩展 @DennisTraub 答案。

SSM parameters resolve in almost all cases in the template, with the exception of UserData (btw, Init will also not work). SSM 参数在模板中的几乎所有情况下都解析,除了UserData (顺便说一句, Init也不起作用)。 This means, that dynamic reference will not resolve when used in the context of UserData .这意味着,在UserData的上下文中使用时,动态引用将无法解析 This is due to security issues.这是由于安全问题。

UserData can be read in plain text by anyone who can view basic attributes of the instance.任何可以查看实例基本属性的人都可以以纯文本形式读取UserData This means, that your JLabPassword would be in plain text available in UserData for everyone to see, if such resolution would be possible.这意味着,您的JLabPassword将以纯文本形式出现在UserData中,供所有人查看,如果这样的解决方案可行的话。

To rectify the issue, the SSM parameters should be used in UserData as follows:为解决此问题,应在UserData中使用 SSM 参数,如下所示:

  1. Attach IAM permission ssm:GetParameter to the instance role/profile which allows instance to access the SSM Parameter Store.将 IAM 权限ssm:GetParameter附加到允许实例访问 SSM 参数存储的实例角色/配置文件。

  2. Instead on {{resolve:ssm:JLabPassword:1}} in your Parameter, you can just pass JLabPassword so that the name of the SSM paramtter gets passed into the UserData , not the actual value of it.而不是在参数中的{{resolve:ssm:JLabPassword:1}}上,您可以只传递JLabPassword以便将 SSM 参数的名称传递给UserData ,而不是它的实际值。

  3. In the UserData , please use AWS CLI get-parameter to get the actual value of your JLabPassword .UserData中,请使用 AWS CLI get-parameter获取JLabPassword的实际值。

The above ensures that the value of JLabPassword is kept private and not visible in plain text in UserData .以上确保JLabPassword的值是私有的,并且在UserData的纯文本中不可见。

Your passwort parameter's default value is missing the service name ( ssm ) as well as single quotes.您的密码参数的默认值缺少服务名称 ( ssm ) 以及单引号。

// What you have:
Password:
  Default: {{resolve:JupyterPassword:1}}
  ...

// What it should be:
Password:
  Default: '{{resolve:ssm:JupyterPassword:1}}'
  ...

Update: You've fixed the code in your question.更新:您已经修复了问题中的代码。 Did my answer and the comments below solve your question?我的回答和下面的评论解决了你的问题吗? If not, I'm not sure what else you need.如果没有,我不确定您还需要什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM