前言
本文将使用一台 Windows Server 2019 服务器实现自建 AD + ADFS 环境集成到中国区 AWS 控制台进行单点登录.
参考文档: https://aws.amazon.com/cn/blogs/china/adfs-bjs/
配置 AD
生产环境建议先给本地连接设置静态 IP 地址, 不设置也没事儿, 后面配置功能的时候会有 Warning 提示, 测试环境忽略不碍事. 管理员身份打开 PowerShell 执行下面命令:
# 重命名主机名 (自动重启)
Rename-Computer -NewName "ADFS" -Restart
# 添加 AD 功能
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
# 创建新的林和名为 alian.com 的域 (需要设置 SafeMode 恢复密码, 自动重启)
Install-ADDSForest -DomainName alian.com -InstallDNS
创建 AD 账号
# 创建新的 OU
New-ADOrganizationalUnit -Name "AWS" -Path "DC=alian,DC=com"
# 创建组
New-ADGroup -Name "AWS-Admin" -Path "OU=AWS,DC=alian,DC=com" -GroupScope Universal
New-ADGroup -Name "AWS-ReadOnly" -Path "OU=AWS,DC=alian,DC=com" -GroupScope Universal
# 创建用户
New-ADUser -Name "awsadmin" -DisplayName "AWS Administartor" -SamAccountName "awsadmin" -EmailAddress "awdadmin@alian.com" -UserPrincipalName "awsadmin@alian.com" -Path "OU=AWS,DC=alian,DC=com" -AccountPassword (ConvertTo-SecureString "Password123#" -AsPlainText -Force) -ChangePasswordAtLogon $false -Enabled $true -PasswordNeverExpires $true
# 将用户添加到组
Add-ADGroupMember -Identity "CN=AWS-Admin,OU=AWS,DC=alian,DC=com" -Members "CN=awsadmin,OU=AWS,DC=alian,DC=com"
New-ADUser
文档: https://learn.microsoft.com/en-us/powershell/module/activedirectory/new-aduser?view=windowsserver2022-ps#examples
Add-ADGroupMember
命令中需要传入包含 OU 信息的完整路径
ADFS 基础配置
# 安装 ADFS 和 IIS 功能
Install-WindowsFeature -Name ADFS-Federation,Web-Server -IncludeManagementTools
# 创建自签名证书
New-SelfSignedCertificate -DnsName "adfs.alian.com" -CertStoreLocation "Cert:\LocalMachine\My"
# 创建 ADFS Farm
$cert = Get-ChildItem -Path cert:\LocalMachine\My | Where-Object { $_.Subject -match "adfs.alian.com" }
Install-AdfsFarm -CertificateThumbprint $cert.Thumbprint -FederationServiceName "adfs.alian.com" -ServiceAccountCredential (Get-Credential -Credential alian\administrator)
# 添加 DNS 解析
$ip = (Get-DnsServerResourceRecord -ZoneName "alian.com" -Name $env:COMPUTERNAME).RecordData.IPv4Address.IPAddressToString
Add-DnsServerResourceRecord -Name "adfs" -ZoneName "alian.com" -A -IPv4Address $ip
安装 Firefox 或 Chrome 浏览器, 访问 https://adfs.alian.com/FederationMetadata/2007-06/FederationMetadata.xml
下载 XML 文件备用.
AWS IAM 配置
打开 IAM 控制台 > Identity providers > Add provider > Provider type: SAML, 起个名字, 打开上一步下载好的 Metadata XML 文件, 保存
保存后, 复制 ARN 信息备用.
再打开 Roles > Create role > Trust entity type 选择 “SAML 2.0 federation”, 下面的 provider 选择上一步创建好的项目, 选择 “Allow programmatic and Amazon Web Services Management Console access” 允许联合登录访问控制台
选择托管策略 AdministratorAccess
, Role name 输入 ADFS-Admin
, Review 一下创建. 注意这里给 Role 起的名称前缀 ADFS-
将会用在后续做信任转换匹配.
复制 Role ARN 后面备用
ADFS 进阶配置
# 添加 Relying Party Trust (信赖方信任)
Add-AdfsRelyingPartyTrust -Name "AWS Console" -MetadataURL "https://signin.amazonaws.cn/static/saml-metadata.xml" -AccessControlPolicyName "Permit everyone"
# 存入变量
$rp = Get-AdfsRelyingPartyTrust -Name "AWS Console"
接下来是重点也是最难搞的一步, 就是配置转换规则, 将 SAML 中解析出来的内容映射到 AWS IAM 可以匹配的 Role. 官方文档里面用的是 GUI 一条一条添加的, 实例规则代码还有一些纰漏, 不如继续用 PowerShell 搞. 注意替换 $rule
中 ARN 和前面 IAM 中的信息保持一致.
$rule = @'
@RuleTemplate = "MapClaims"
@RuleName = "NameId"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent");
@RuleTemplate = "LdapClaims"
@RuleName = "RoleSessionName"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("https://aws.amazon.com/SAML/Attributes/RoleSessionName"), query = ";mail;{0}", param = c.Value);
@RuleName = "Get AD Groups"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = ("http://temp/variable"), query = ";tokenGroups;{0}", param = c.Value);
@RuleName = "Roles"
c:[Type == "http://temp/variable", Value =~ "(?i)^AWS-"]
=> issue(Type = "https://aws.amazon.com/SAML/Attributes/Role", Value = RegExReplace(c.Value, "AWS-", "arn:aws-cn:iam::123123123123:saml-provider/alian.com-adfs,arn:aws-cn:iam::123123123123:role/ADFS-"));
'@
Set-AdfsRelyingPartyTrust -TargetRelyingParty $rp -IssuanceTransformRules $rule
# 开启 SingonPage 否则会出现后面无法登录的错误
Set-AdfsProperties -EnableIdpInitiatedSignonPage $true
# 重启 ADFS 服务
Restart-Service adfssrv
测试访问
使用 Firefox 访问 https://adfs.alian.com/adfs/ls/IdpInitiatedSignOn.aspx
填坑
如果没有执行前面Set-AdfsProperties -EnableIdpInitiatedSignonPage $true
登录后会报错:
Activity ID: 9c0aa720-9776-4b96-0700-0080000000fb
Error details: MSIS7012: An error occurred while processing the request. Contact your administrator for details.
Node name: 7440faec-1a4f-4023-b34c-caf6be8fada7
Error time: Wed, 22 May 2024 14:18:13 GMT
Cookie: enabled
User agent string: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0
# 检查 ADFS 属性, 默认并没有开启 SingonPage
Get-AdfsProperties | Select-Object -Property EnableIdpInitiatedSignonPage
# 打开
Set-AdfsProperties -EnableIdpInitiatedSignonPage $true