从另一个 AWS 账户编辑 EC2 安全组
Edit EC2 security group from another AWS account
我在 AWS 上有 2 个账户。在第一个帐户上,我创建了一个带有 "dbSG" 安全组的永久 EC2 实例(仅允许通过特定端口和 IP 进行连接)。
当我使用 CloudFormation 模板在第二个帐户中创建实例时,它应该:
- 将此实例 IP 添加到 "dbSG" 安全组并允许通过特定端口连接。
- 通过此端口连接到第一个实例。
我可以在第二个帐户中创建实例时在 UserData 中使用 AssumeRole 并修改 "dbSG" 以允许来自该实例的连接吗?如果是,如何逐步完成?
看来你的情况是:
- 两个VPC,我们称它们为:VPC-A和VPC-B
- 每个 VPC 都属于不同的 AWS 账户
- 实例-A 存在于 VPC-A 中,具有安全组
dbSG
- 在VPC-B中启动Instance-B时,允许其访问Instance-A
实现此目的的最简单方法是通过 VPC Peering,它允许同一区域中的两个 VPC 之间直接通信。 VPC 可以属于不同的 AWS 账户,但 IP 地址范围必须不重叠。
过程将是:
- VPC-A 邀请 VPC-B 对等
- VPC-B 接受邀请
- Update routing tables 在两个 VPC 中相互发送流量
- 在VPC-B中创建一个安全组,例如
appSG
- 修改
dbSG
以允许来自 appSG
的传入连接
- 将实例 B(以及任何其他应与实例 A 通信的实例)与
appSG
安全组关联
就是这样! 安全性在对等 VPC 之间的工作方式与在 VPC 内的工作方式相同。唯一的区别是这些实例位于相互对等的单独 VPC 中。
对于EC2-Classic
ec2 authorize-security-group-ingress
的 CLI 帮助有这个例子:
To add a rule that allows inbound HTTP traffic from a security
group in another account
This example enables inbound traffic on TCP port 80 from a source
security group (otheraccountgroup) in a different AWS
account (123456789012). If the command succeeds, no output is
returned.
Command:
aws ec2 authorize-security-group-ingress --group-name
MySecurityGroup --protocol tcp --port 80 --source- group
otheraccountgroup --group-owner 123456789012
因此,假设您知道 "appSG" 的安全组 ID,以及来自 "db" 帐户的凭据:
aws ec2 authorize-security-group-ingress --group-name
dbSG --protocol tcp --port 1234 --source-group
appSG --group-owner XXX-APP-ACCOUNT-ID
通过 CloudFormation:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group-rule.html#cfn-ec2-security-group-rule-sourcesecuritygroupownerid
不幸的是,这似乎不适用于 VPC 中的实例,但仅适用于 EC2-Classic。
对于 EC2-VPC:user-data
方式
在 "db" 账户中,将角色添加到您的 CF 模板,指定允许此类角色由另一个 AWS 账户中的特定角色承担的信任策略:
(将 XXX-... 替换为您自己的值)
'RoleForOtherAccount': {
'Type': 'AWS::IAM::Role',
'Properties': {
'AssumeRolePolicyDocument': {
'Version': '2012-10-17',
'Statement': [{
'Effect': 'Allow',
'Principal': {
'AWS': "arn:aws:iam::XXX-OTHER-AWS-ACCOUNT-ID:role/XXX-ROLE-NAME-GIVEN-TO-APP-INSTANCES"
},
'Action': ['sts:AssumeRole']
}]
},
'Path': '/',
'Policies': [{
'PolicyName': 'manage-sg',
'PolicyDocument': {
'Version': '2012-10-17',
'Statement': [
{
'Effect': 'Allow',
'Action': [
'ec2: AuthorizeSecurityGroupIngress'
],
'Resource': '*'
}
]
}
}]
}
}
然后,在 "app" 实例上,您可以添加以下用户数据脚本(通过 CloudFormation:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-userdata)
#!/bin/bash
# get current public IP address via EC2 meta-data
MY_IP=$(wget -qO- http://instance-data/latest/meta-data/public-ipv4)
# assume the "db" account role and get the credentials
CREDENTIALS_JSON=$(aws sts assume-role --role-arn XXX-ARN-OF-ROLE-IN-DB-ACCOUNT --role-session-name "AppSessionForSGIngress" --query '{"AWS_ACCESS_KEY_ID": Credentials.AccessKeyId, "AWS_SECRET_ACCESS_KEY": Credentials.SecretAccessKey, "AWS_SESSION_TOKEN": Credentials.SessionToken }')
# here you should find a way to extract AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN from the above $CREDENTIALS_JSON, then export them or pass as values replacing YYY below
# authorize the IP
aws --region XXX-DB-REGION --access-key-id YYY --secret-access-key YYY --session-token YYY ec2 authorize-security-group-ingress --group-id sg-XXX --protocol tcp --port 1234 --cidr $MY_IP/32
"app" 实例的 IAM 角色必须允许调用 sts:AssumeRole
。
警告: 如果您停止并重新启动实例,其 public IP 将会更改(除非您已分配 ElasticIP)。由于用户数据脚本仅在第一次启动期间执行,因此您的 dbSG 不会更新。
通过 Lambda
您也可以使用由 CloudTrail 或 Config 触发的 Lambda 函数,尽管这有点棘手:
这样,您还可以跟踪对 StopInstance 和 StartInstance 的调用,并以更稳健的方式更新 (revoke/authorize) dbSG 规则。
参考文献:
我在 AWS 上有 2 个账户。在第一个帐户上,我创建了一个带有 "dbSG" 安全组的永久 EC2 实例(仅允许通过特定端口和 IP 进行连接)。
当我使用 CloudFormation 模板在第二个帐户中创建实例时,它应该:
- 将此实例 IP 添加到 "dbSG" 安全组并允许通过特定端口连接。
- 通过此端口连接到第一个实例。
我可以在第二个帐户中创建实例时在 UserData 中使用 AssumeRole 并修改 "dbSG" 以允许来自该实例的连接吗?如果是,如何逐步完成?
看来你的情况是:
- 两个VPC,我们称它们为:VPC-A和VPC-B
- 每个 VPC 都属于不同的 AWS 账户
- 实例-A 存在于 VPC-A 中,具有安全组
dbSG
- 在VPC-B中启动Instance-B时,允许其访问Instance-A
实现此目的的最简单方法是通过 VPC Peering,它允许同一区域中的两个 VPC 之间直接通信。 VPC 可以属于不同的 AWS 账户,但 IP 地址范围必须不重叠。
过程将是:
- VPC-A 邀请 VPC-B 对等
- VPC-B 接受邀请
- Update routing tables 在两个 VPC 中相互发送流量
- 在VPC-B中创建一个安全组,例如
appSG
- 修改
dbSG
以允许来自appSG
的传入连接
- 将实例 B(以及任何其他应与实例 A 通信的实例)与
appSG
安全组关联
就是这样! 安全性在对等 VPC 之间的工作方式与在 VPC 内的工作方式相同。唯一的区别是这些实例位于相互对等的单独 VPC 中。
对于EC2-Classic
ec2 authorize-security-group-ingress
的 CLI 帮助有这个例子:
To add a rule that allows inbound HTTP traffic from a security group in another account
This example enables inbound traffic on TCP port 80 from a source security group (otheraccountgroup) in a different AWS account (123456789012). If the command succeeds, no output is returned.
Command:
aws ec2 authorize-security-group-ingress --group-name MySecurityGroup --protocol tcp --port 80 --source- group otheraccountgroup --group-owner 123456789012
因此,假设您知道 "appSG" 的安全组 ID,以及来自 "db" 帐户的凭据:
aws ec2 authorize-security-group-ingress --group-name
dbSG --protocol tcp --port 1234 --source-group
appSG --group-owner XXX-APP-ACCOUNT-ID
通过 CloudFormation:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group-rule.html#cfn-ec2-security-group-rule-sourcesecuritygroupownerid
不幸的是,这似乎不适用于 VPC 中的实例,但仅适用于 EC2-Classic。
对于 EC2-VPC:user-data
方式
在 "db" 账户中,将角色添加到您的 CF 模板,指定允许此类角色由另一个 AWS 账户中的特定角色承担的信任策略:
(将 XXX-... 替换为您自己的值)
'RoleForOtherAccount': {
'Type': 'AWS::IAM::Role',
'Properties': {
'AssumeRolePolicyDocument': {
'Version': '2012-10-17',
'Statement': [{
'Effect': 'Allow',
'Principal': {
'AWS': "arn:aws:iam::XXX-OTHER-AWS-ACCOUNT-ID:role/XXX-ROLE-NAME-GIVEN-TO-APP-INSTANCES"
},
'Action': ['sts:AssumeRole']
}]
},
'Path': '/',
'Policies': [{
'PolicyName': 'manage-sg',
'PolicyDocument': {
'Version': '2012-10-17',
'Statement': [
{
'Effect': 'Allow',
'Action': [
'ec2: AuthorizeSecurityGroupIngress'
],
'Resource': '*'
}
]
}
}]
}
}
然后,在 "app" 实例上,您可以添加以下用户数据脚本(通过 CloudFormation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-userdata)
#!/bin/bash
# get current public IP address via EC2 meta-data
MY_IP=$(wget -qO- http://instance-data/latest/meta-data/public-ipv4)
# assume the "db" account role and get the credentials
CREDENTIALS_JSON=$(aws sts assume-role --role-arn XXX-ARN-OF-ROLE-IN-DB-ACCOUNT --role-session-name "AppSessionForSGIngress" --query '{"AWS_ACCESS_KEY_ID": Credentials.AccessKeyId, "AWS_SECRET_ACCESS_KEY": Credentials.SecretAccessKey, "AWS_SESSION_TOKEN": Credentials.SessionToken }')
# here you should find a way to extract AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN from the above $CREDENTIALS_JSON, then export them or pass as values replacing YYY below
# authorize the IP
aws --region XXX-DB-REGION --access-key-id YYY --secret-access-key YYY --session-token YYY ec2 authorize-security-group-ingress --group-id sg-XXX --protocol tcp --port 1234 --cidr $MY_IP/32
"app" 实例的 IAM 角色必须允许调用 sts:AssumeRole
。
警告: 如果您停止并重新启动实例,其 public IP 将会更改(除非您已分配 ElasticIP)。由于用户数据脚本仅在第一次启动期间执行,因此您的 dbSG 不会更新。
通过 Lambda
您也可以使用由 CloudTrail 或 Config 触发的 Lambda 函数,尽管这有点棘手:
这样,您还可以跟踪对 StopInstance 和 StartInstance 的调用,并以更稳健的方式更新 (revoke/authorize) dbSG 规则。
参考文献: