亚马逊AWS官方博客

AWS ParallelCluster 与 AWS Directory Services 身份验证结合使用

AWS ParallelCluster 可简化 HPC 集群的创建和部署。在此博文中,我们将 ParallelCluster 与 AWS Directory Services 结合以创建具有集中身份验证和自动化主目录创建的多用户、POSIX 兼容系统。

为了只向集群中的阶段授权最低权限,没有将 AD 配置参数或权限直接存储在集群节点上。反之,ParallelCluster 节点在启用时将自动触发 AWS Lambda 函数,该函数反过来会使用 AWS Systems Manager Parameter StoreAWS KMS 将节点安全加入到域中。用户将使用其 AD 凭证登录 ParallelCluster 节点。

ParallelCluster 的 VPC 配置

用于此配置的 VPC 可以使用“VPC 向导”工具创建。您也可以使用符合 AWS ParallelCluster 网络要求的现有 VPC。

 

 

选择 VPC 配置中,选择具有公共和私有子网的 VPC,然后点击选择

 

在开始 VPC 向导之前,分配一个 弹性 IP 地址。该地址将被用于为私有子网配置 NAT 网关。在 AWS ParallelCluster 私有子网中启用计算节点以下载所需软件包和访问 AWS 服务公共终端节点时,需要 NAT 网关。请参见 AWS ParallelCluster 网络要求

请务必为公共和私有子网选择两个不同的可用区。虽然 ParallelCluster 本身并不严格要求这样做,但稍后我们会将这些子网再次用于 SimpleAD,这就需要子网处于两个不同的可用区中。

 

您可以在具有公共和私有子网 (NAT) 的 VPC 中了解有关 VPC 创建和配置选项的更多详细信息。

AWS Directory Services 配置

为简单起见,在本示例中,我们将 Simple AD 配置为目录服务,但此解决方案将适用于任何 Active Directory 系统。

Simple AD 配置可通过 AWS Directory Service 控制台执行。所需的配置步骤见 Simple AD 入门所述。

在此示例中,将 Simple AD 配置设置如下:

目录 DNS 名称:test.domain
目录 NetBIOS 名称:TEST
管理员密码:<Your DOMAIN password>

 

 

在联网部分中,选择 VPC 和前述步骤中创建的两个子网。

以下屏幕截图包含目录详细信息:

 

请记下目录详细信息中列出的 DNS 地址,因为稍后将需要这些地址(在此示例中为 10.0.0.92 和 10.0.1.215)。

为 AD 设置的 DHCP 选项

为了使节点加入 AD 域中,必须为 VPC 配置 DHCP 选项集,该选项集要与以前配置的 Simple AD 服务的域名和 DNS 一致。

AWS VPC 控制面板中,设置以下各项:

名称:自定义的 DHCP 选项集
域名: test.domain eu-west-1.compute.internal
域名服务器:10.0.0.92、10.0.1.215

“域名”字段必须包含 Simple AD 域和 AWS 区域性域(集群和 SimpleAD 在其中配置),中间用空格隔开。

 

 

现在,您可以将新的 DHCP 选项集分配到 VPC 中:

 

如何在 Simple Active Directory 中管理用户和组

请参阅在 Simple AD 中管理用户和组。如果您更喜欢使用 Linux OS 进行账户管理,请参阅如何在 Simple AD 目录中管理身份以了解详情。

使用 AWS Key Management Service 保护 AD Domain 加入凭证

AWS Key Management Service 是一项安全且具有弹性的服务,使用经 FIPS 140-2 验证的硬件安全模块来保护您的密钥。此服务将用于生成密钥和对域加入密码进行加密,如下一部分所述。

在 AWS 控制台中,导航至 AWS Key Management Service (KMS) 并点击创建密钥

显示密钥的名称中,输入“SimpleADJoinPassword”并点击下一步,保留所有其他部分的默认设置。

客户托管的密钥中,记下已创建的 密钥 ID

 

AWS Systems Manager Parameter Store

AWS Systems Manager Parameter Store 可为配置数据管理和密钥管理提供安全的分层存储。我们将用它安全存储域加入信息,即域名和加入密码。

从 AWS 控制台中,访问 AWS Systems Manager 并选择 Parameter Store。您需要创建两个特定参数:包含域名的 DomainName 和包含域管理员密码的 DomainPassword

要创建第一个参数,点击创建参数并在参数详细信息部分中添加下列信息:

名称: DomainName
类型:String
值:test.domain

点击创建参数以创建参数。

现在,您可以用以下详细信息创建 DomainPassword 参数:

名称:DomainPassword
类型:SecureString
KMS 密钥 ID:alias/SimpleADJoinPassword
值:<your_ad_password>

点击创建参数以创建参数。

结果应与下面的屏幕截图类似:

 

AWS ParallelCluster 配置

AWS ParallelCluster 是一种开源集群管理工具,可用于在 AWS 云中部署和管理 HPC 集群;要开始使用,请参阅安装 AWS ParallelCluster

在配置好 AWS ParallelCluster 命令行之后,在 .parallelcluster/config 中创建下面提供的集群模板文件。master_subnet_id 包含已创建公共子网的 ID;compute_subnet_id 包含私有 ID。

ec2_iam_role 是将用于集群所有实例的角色。创建此角色的步骤将在下一部分中说明。

[aws]
aws_region_name = eu-west-1

[cluster slurm]
scheduler = slurm
compute_instance_type = c5.large
initial_queue_size = 2
max_queue_size = 10
maintain_initial_size = false
base_os = alinux
key_name = AWS_Ireland
vpc_settings = public
ec2_iam_role = parallelcluster-custom-role
pre_install = s3://pcluster-scripts/pre_install.sh
post_install = s3://pcluster-scripts/post_install.sh

[vpc public]
master_subnet_id = subnet-01fc20e143543f8af
compute_subnet_id = subnet-0b1ae2790497d83ec
vpc_id = vpc-0cdee679c5a6163bd

[global]
update_check = true
sanity_check = true
cluster_template = slurm

[aliases]
ssh = ssh {CFN_USER}@{MASTER_IP} {ARGS}

s3://pcluster-scripts 存储桶包含在域内配置主节点和计算节点所需的安装前和安装后脚本。需要唯一的存储桶名称 – 创建 S3 存储桶并将 s3://pcluster-scripts 替换为您选择的名称。

pre_install 脚本可安装所需的软件包并将阶段加入域内:

#!/bin/bash

# 安装所需的软件包
yum -y install sssd realmd krb5-workstation samba-common-tools
instance_id=$(curl http://169.254.169.254/latest/meta-data/instance-id)
region=$(curl  -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/[a-z]$//')
# 用于在域中加入 Linux 系统的 Lambda 函数
aws --region ${region} lambda invoke --function-name join-domain-function /tmp/out --payload '{"instance": "'${instance_id}'"}' --log-type None
output=""
while [ -z "$output" ]
do
  sleep 5
  output=$(realm list)
done
# 此行可使用户在没有域名的情况下登录
sed -i 's/use_fully_qualified_names = True/use_fully_qualified_names = False/g' /etc/sssd/sssd.conf
# 此行将 sssd 配置为在共享文件夹中创建主目录
mkdir /shared/home/
sed -i '/fallback_homedir/c\fallback_homedir = /home/%u' /etc/sssd/sssd.conf
sleep 1
service sssd restart
# AWS Parallel 集群需要此行来正确了解自定义域
sed -i "s/--fail \${local_hostname_url}/--fail \${local_hostname_url} | awk '{print \$1}'/g" /opt/parallelcluster/scripts/compute_ready

post_install 脚本可将 ssh 服务配置为接受带有密码的连接:

#!/bin/bash

sed -i 's/PasswordAuthentication no//g' /etc/ssh/sshd_config
echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
sleep 1
服务 sshd 重启

pre_installpost_install 脚本复制到以前创建的 S3 存储桶。

AD 域加入 AWS Lambda

AWS Lambda 允许您在无预置或管理服务器的情况下运行代码。此解决方案使用 Lambda 将 Linux 节点安全地加入 Simple AD 域中。

您可以使用控制台创建 Lambda 函数

对于函数名称,请输入 join-domain-function。

对于运行时,请输入 Python 2.7。

选择“创建函数”以创建函数。

 

下面的代码应输入在函数代码部分中,您可以在页面中向下滚动找到代码。请用正确的值修改 <REGION>。

import json
import boto3
import time

def lambda_handler(event, context):
    json_message = json.dumps(event)
    message = json.loads(json_message)
    instance_id = message['instance']
    ssm_client = boto3.client('ssm', region_name="<REGION>") # 使用您工作所在区域的代码
    DomainName = ssm_client.get_parameter(Name='DomainName')
    DomainName_value = DomainName['Parameter']['Value']
    DomainPassword = ssm_client.get_parameter(Name='DomainPassword',WithDecryption=True)
    DomainPassword_value = DomainPassword['Parameter']['Value']
    response = ssm_client.send_command(
             InstanceIds=[
                "%s"%instance_id
                     ],
             DocumentName="AWS-RunShellScript",
             Parameters={
                'commands':[
                     'echo "%s" | realm join -U Administrator@%s %s --verbose;rm -rf /var/lib/amazon/ssm/i-*/document/orchestration/*'%(DomainPassword_value,DomainName_value,DomainName_value)                       ]
                  },
               )
    return {
        'statusCode': 200,
        'body': json.dumps('Command Executed!')
    }

基本设置部分中,将 10 秒设置为超时

点击右上角的保存以保存函数。

执行角色部分中,点击高亮显示的部分以编辑角色。

 

 

在新打开的选项卡中,点击附加策略,然后点击创建策略

 

最后一个操作会在您的浏览器中打开另一个新选项卡。

点击创建策略,然后点击 JSON

 

 

可以在 JSON 编辑器内输入以下策略。请用正确的值修改 <REGION>、<AWS ACCOUNT ID> 和 <KEY ID>。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter"
            ],
            "Resource": [
                "arn:aws:ssm:<REGION>:<AWS ACCOUNT ID>:parameter/DomainName"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter"
            ],
            "Resource": [
                "arn:aws:ssm:<REGION>:<AWS ACCOUNT ID>:parameter/DomainPassword"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:SendCommand"
            ],
            "Resource": [
                "arn:aws:ec2:<REGION>:<AWS ACCOUNT ID>:instance/*",
                "arn:aws:ssm:<REGION>::document/AWS-RunShellScript"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:<REGION>:<AWS ACCOUNT ID>:key/<KEY ID>"
            ]
        }
    ]
}

在下一部分中,输入“GetJoinCredentials”作为名称,然后点击创建策略

关闭当前选项卡并移动到上一个选项卡,以为 Lambda 角色选择策略。

刷新列表,选择 GetJoinCredentials 策略,并点击附加策略

 

Lambda 和 SSM 终端节点的 IAM 自定义角色

要允许 ParallelCluster 节点调用 Lambda 和 SSM 终端节点,您需要配置自定义 IAM 角色

请参阅 AWS ParallelCluster 中的 AWS Identity and Access Management 角色了解默认 AWS ParallelCluster 策略的详细信息。

从 AWS 控制台中:

  • 访问 AWS Identity and Access Management (IAM) 服务并点击策略
  • 选择创建策略,并在 JSON 部分中,粘贴以下策略。务必修改 <REGION><AWS ACCOUNT ID>,以匹配您的账户值,同时将 S3 存储桶名称从 pcluster-scripts 更新为您之前选择的名称。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Resource": [
                "*"
            ],
            "Action": [
                "ec2:DescribeVolumes",
                "ec2:AttachVolume",
                "ec2:DescribeInstanceAttribute",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:DescribeRegions"
            ],
            "Sid": "EC2",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "*"
            ],
            "Action": [
                "dynamodb:ListTables"
            ],
            "Sid": "DynamoDBList",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "arn:aws:sqs:<REGION>:<AWS ACCOUNT ID>:parallelcluster-*"
            ],
            "Action": [
                "sqs:SendMessage",
                "sqs:ReceiveMessage",
                "sqs:ChangeMessageVisibility",
                "sqs:DeleteMessage",
                "sqs:GetQueueUrl"
            ],
            "Sid": "SQSQueue",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "*"
            ],
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:DescribeTags",
                "autoScaling:UpdateAutoScalingGroup",
                "autoscaling:SetInstanceHealth"
            ],
            "Sid": "Autoscaling",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "arn:aws:dynamodb:<REGION>:<AWS ACCOUNT ID>:table/parallelcluster-*"
            ],
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:GetItem",
                "dynamodb:DeleteItem",
                "dynamodb:DescribeTable"
            ],
            "Sid": "DynamoDBTable",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "arn:aws:s3:::<REGION>-aws-parallelcluster/*"
            ],
            "Action": [
                "s3:GetObject"
            ],
            "Sid": "S3GetObj",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "arn:aws:cloudformation:<REGION>:<AWS ACCOUNT ID>:stack/parallelcluster-*"
            ],
            "Action": [
                "cloudformation:DescribeStacks"
            ],
            "Sid": "CloudFormationDescribe",
            "Effect": "Allow"
        },
        {
            "Resource": [
                "*"
            ],
            "Action": [
                "sqs:ListQueues"
            ],
            "Sid": "SQSList",
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:DescribeAssociation",
                "ssm:GetDeployablePatchSnapshotForInstance",
                "ssm:GetDocument",
                "ssm:DescribeDocument",
                "ssm:GetManifest",
                "ssm:GetParameter",
                "ssm:GetParameters",
                "ssm:ListAssociations",
                "ssm:ListInstanceAssociations",
                "ssm:PutInventory",
                "ssm:PutComplianceItems",
                "ssm:PutConfigurePackageResult",
                "ssm:UpdateAssociationStatus",
                "ssm:UpdateInstanceAssociationStatus",
                "ssm:UpdateInstanceInformation"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2messages:AcknowledgeMessage",
                "ec2messages:DeleteMessage",
                "ec2messages:FailMessage",
                "ec2messages:GetEndpoint",
                "ec2messages:GetMessages",
                "ec2messages:SendReply"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "arn:aws:lambda:<REGION>:<AWS ACCOUNT ID>:function:join-domain-function"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::pcluster-scripts/*"
            ]
        }
    ]
}

点击查看策略,并在下一部分中输入“parallelcluster-custom-policy”作为名称字符串。点击创建策略

现在,您终于可以创建角色了。在左侧菜单中选择角色,然后选择创建角色

选择 AWS 服务作为受信任实体的类型,并选择 EC2 作为将使用此角色的服务。

选择下一步继续创建过程。

 

 

在策略选择中,选择刚创建的 parallelcluster-custom-policy

点进下一步:标签中,然后点进下一步:查看页面。

角色名称框中,输入“parallelcluster-custom-role”并使用创建角色按钮进行确认。

部署 ParallelCluster

现在,可以使用以下命令行创建集群:

pcluster create -t slurm slurmcluster

-t slurm 指示要使用集群模板的哪个部分。slurmcluster 是将创建的集群名称。如需了解详情,请参阅 AWS ParallelCluster 文档。pcluster 命令行参数的具体说明可参见 AWS ParallelCluster CLI 命令

现在,您可以将集群主节点连接到任何 Simple AD 用户并运行所需工作负载。

清除

当您完成计算时,可以使用以下命令销毁集群:

pcluster delete slurmcluster

其他已创建的资源可以按照 AWS 文档中的说明销毁:

小结

此博文向您展示如何部署并将 Simple AD 与 AWS ParallelCluster 集成,从而使集群节点被安全、自动地加入到域中,以提供集中用户身份验证。此解决方案使用 AWS Systems Manager Parameter StoreAWS KMS 加密并存储域加入凭证,并在节点启动时使用 AWS Lambda 加入 AD 域。