Cloudformation 堆栈默认参数 SSM Parameter store
Cloudformation stack default parameter SSM Parameter store
我正在尝试使用 cloudformation 启动一个 jupyterlab 实例(这是我经常做的事情,而 sagemaker 没有 1y 免费套餐)所以开头看起来像这样不起作用。特别是密码参数
# 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
然而,它按字面解释字符串,所以我实际上并没有得到我的密码,而是解析...本身。
您的密码参数的默认值缺少服务名称 (ssm
) 和单引号。
// What you have:
Password:
Default: {{resolve:JupyterPassword:1}}
...
// What it should be:
Password:
Default: '{{resolve:ssm:JupyterPassword:1}}'
...
更新:您已修复问题中的代码。我的回答和下面的评论是否解决了您的问题?如果没有,我不确定你还需要什么。
基于 OP 的评论和新的、更新的模板,并扩展@DennisTraub 的回答。
SSM parameters 在模板中的几乎所有情况下都会解析,但 UserData
除外(顺便说一句,Init
也不起作用)。这意味着,当在 UserData
的上下文中使用时,动态引用将 不会解析 。这是由于安全问题。
UserData
任何可以查看实例基本属性的人都可以在 纯文本 中阅读。这意味着,您的 JLabPassword
将以纯文本形式在 UserData
中提供给所有人查看,如果这样的解决方案是可能的话。
要纠正此问题,应在 UserData
中使用 SSM 参数,如下所示:
将 IAM 权限 ssm:GetParameter
附加到实例 role/profile 以允许实例访问 SSM Parameter Store。
而不是 {{resolve:ssm:JLabPassword:1}}
在你的参数中,你可以只传递 JLabPassword
这样 SSM 参数的名称就会传递到 UserData
,而不是它的实际价值。
在UserData
中,请使用AWS CLI get-parameter获取你的JLabPassword
的实际值。
以上确保 JLabPassword
的值在 UserData
.
中保持私有并且在纯文本中不可见
我正在尝试使用 cloudformation 启动一个 jupyterlab 实例(这是我经常做的事情,而 sagemaker 没有 1y 免费套餐)所以开头看起来像这样不起作用。特别是密码参数
# 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
然而,它按字面解释字符串,所以我实际上并没有得到我的密码,而是解析...本身。
您的密码参数的默认值缺少服务名称 (ssm
) 和单引号。
// What you have:
Password:
Default: {{resolve:JupyterPassword:1}}
...
// What it should be:
Password:
Default: '{{resolve:ssm:JupyterPassword:1}}'
...
更新:您已修复问题中的代码。我的回答和下面的评论是否解决了您的问题?如果没有,我不确定你还需要什么。
基于 OP 的评论和新的、更新的模板,并扩展@DennisTraub 的回答。
SSM parameters 在模板中的几乎所有情况下都会解析,但 UserData
除外(顺便说一句,Init
也不起作用)。这意味着,当在 UserData
的上下文中使用时,动态引用将 不会解析 。这是由于安全问题。
UserData
任何可以查看实例基本属性的人都可以在 纯文本 中阅读。这意味着,您的 JLabPassword
将以纯文本形式在 UserData
中提供给所有人查看,如果这样的解决方案是可能的话。
要纠正此问题,应在 UserData
中使用 SSM 参数,如下所示:
将 IAM 权限
ssm:GetParameter
附加到实例 role/profile 以允许实例访问 SSM Parameter Store。而不是
{{resolve:ssm:JLabPassword:1}}
在你的参数中,你可以只传递JLabPassword
这样 SSM 参数的名称就会传递到UserData
,而不是它的实际价值。在
UserData
中,请使用AWS CLI get-parameter获取你的JLabPassword
的实际值。
以上确保 JLabPassword
的值在 UserData
.