4

我正在尝试使用 AWS 的云开发工具包为我网站的某些子域创建 SSL 证书。问题是我正在使用 AWS Organizations 并且相关资源属于不同的 AWS 账户。我的域的托管区域是我们主帐户的一部分,但我正在运行 CDK 以在链接帐户中部署堆栈。这意味着DnsValidatedCertificate 该类能够请求一个新证书(在堆栈回滚后它们仍然在ACM中可见),但是当它尝试创建 DNS 记录以自动验证请求时会引发错误。

这是错误(我的帐号和堆栈名称已编辑):

 5/6 | 22:44:14 | CREATE_FAILED        | AWS::CloudFormation::CustomResource | SubSubDomainsCertificate/CertificateRequestorResource/Default (SubSubDomainsCertificateCertificateRequestorResourceBC626C85) Failed to create resource. User: arn:aws:sts::123456789012:assumed-role/MyStack-SubSubDomainsCertificateCertificat-16QRI74P8POO2/MyStack-SubSubDomainsCertificateCertificat-BXZ55WHIH1XC is not authorized to access this resource
        new CustomResource (C:\repos\my-project\node_modules\@aws-cdk\aws-cloudformation\lib\custom-resource.ts:92:21)
        \_ new DnsValidatedCertificate (C:\repos\my-project\node_modules\@aws-cdk\aws-certificatemanager\lib\dns-validated-certificate.ts:81:29)
        \_ new MyStack (C:\repos\my-project\.elasticbeanstalk\api-stack.js:91:25)

这是相关的 CDK 代码(同样,HZ 和域已编辑):

    // Executed with `cdk deploy --profile profileForLinkedAwsAccount`
    const hostedZone = route53.HostedZone.fromHostedZoneAttributes(
      this,
      'MyDomainHostedZone',
      {
        hostedZoneId: 'Z2ABC1234RYN', // in master AWS account
        zoneName: 'mydomain.com.'
      }
    );
    const certificate = new certificatemanager.DnsValidatedCertificate(
      this,
      'SubSubDomainsCertificate',
      {
        domainName: `*.demo.mydomain.com`,
        hostedZone,
        region: 'us-east-1',
        validationMethod: certificatemanager.ValidationMethod.DNS // ???
      }
    );

那么,是否有任何方法可以配置 CDK 以允许 DNS 验证自动发生?或者我是否需要使用不同的配置文件作为第二步?

编辑:根据迈克尔的建议,我添加了一个名为AWS账户LinkedAccountCertValidatorRole的角色。我附加到角色的托管策略及其信任关系如下所示。不幸的是,我仍然遇到同样的错误。此外,Access Advisor 选项卡表明该角色从未使用过该策略。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "route53:ChangeResourceRecordSets",
            "Resource": "arn:aws:route53:::hostedzone/Z2ABC1234RYN"
        }
    ]
}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}
4

4 回答 4

3

为了完整起见,我将在此处发布简单的答案:使用Certificate类而不是DnsValidatedCertificate。我可以让 CDK 创建一个证书请求,但不能让它尝试自动验证子域。这意味着我必须:

  1. 在关联账户的Amazon Certificate Manager中查找请求,
  2. 检查(或导出)它要求添加的 CNAME 记录,以及
  3. 切换到主 AWS 账户并在Route53中添加记录。
// Executed with `cdk deploy --profile profileForLinkedAwsAccount`
const certificate = new certificatemanager.Certificate(this, 'SubSubDomainsCertificate', {
  domainName: `*.${SUBDOMAIN}.mydomain.com`,
  validationMethod: ValidationMethod.DNS
});

我现在已经选择了这个选项,但是完全自动化这个过程会很好。

于 2019-09-26T07:49:10.103 回答
1

IAM 可能很难做到正确。首先,您创建的角色必须与用户/帐户/组具有信任关系,才能承担该角色。我没有看到您在 OP 中提到过这一点。我不知道 CDK 是什么,所以我无法清楚地了解您在做什么。

角色有权执行可以执行的操作。还有一个信任关系部分定义了谁或什么可以担任该角色。

受信任的关系应该映射到 orgs 主帐户,例如....

在附加权限的主帐户中创建角色:

My_Role_To_Assume
Assign Permissions in Master:

Trust Relationship(Master Account)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::0123456789012:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

在主帐户中创建一个组,并将用户分配到该组。组权限,应该有一个策略文档,显示允许用户承担的角色和子帐号。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "sts:AssumeRole"
      ],
      "Resource": [
        "arn:aws:iam::987654321098:role/My_Role_To_Assume",
        "arn:aws:iam::567890123456:role/My_Other_Role_Assume"
      ]
    }
  ]
}

然后在您希望角色能够访问的帐户中。创建一个具有相同名称的角色(不一定是,但更容易记住这些角色的用途)。

My_Role_To_Assume
Assign Permissions for role in sub-account:

Attach Trust Realtionship policy for sub-account role to trust master account:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::0123456789012:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

您可以调整每个帐户中的权限集,以提供对资源的更细粒度的控制/访问。通常在主账户中,您可能没有任何权限,但 IAM 密码、密钥管理等除外。

这种方法效果很好,总体要点是您在根级别创建信任关系,但主账户中的组策略规定该用户/组可以在子账户中承担哪些角色。

由于您使用的是 CLI,因此在创建或更新子账户中的资源之前,您必须发出 aws sts 调用来承担该角色。有一些脚本可以为您处理这个问题。

例子:

#! /bin/bash
#
# Dependencies:
#   yum install -y jq
#
# Setup:
#   chmod +x ./assume_cloudadmin_role.sh
#
# Execute:
#   source ./assume_cloudadmin_role.sh
#
# Description:
#   Makes assuming an AWS IAM role (+ exporting new temp keys) easier. You're users access key and secret must allow you to assume the role in the sts CLI call.

unset  AWS_SESSION_TOKEN
export AWS_ACCESS_KEY_ID=<place_your_key_here> #Master Account API Key
export AWS_SECRET_ACCESS_KEY=<place_your_secret_here>#Master Account API Secret
export AWS_REGION=us-east-1

temp_role=$(aws sts assume-role \
                    --role-arn "arn:aws:iam::0123456789012:role/My_Role_To_Assume" \
                    --role-session-name "temp_cli_role")

export AWS_ACCESS_KEY_ID=$(echo $temp_role | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $temp_role | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $temp_role | jq -r .Credentials.SessionToken)

env | grep -i AWS_

此调用将设置您的访问密钥和秘密 + 会话令牌以对子帐户执行操作。

希望你得到它的工作!

于 2019-09-25T15:34:57.273 回答
0

CDK v2 有一个CrossAccountZoneDelegationRecord类,允许您设置角色,与 Michael Quale 的答案非常相似,但完全在 CDK 中。

从 API 文档:

要将 NS 记录添加到不同帐户中的 HostedZone,您可以执行以下操作:

在包含父托管区域的账户中:

const parentZone = new route53.PublicHostedZone(this, 'HostedZone', {
  zoneName: 'someexample.com',
  crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('12345678901'),
  crossAccountZoneDelegationRoleName: 'MyDelegationRole',
});

在包含要委托的子区域的帐户中:

const subZone = new route53.PublicHostedZone(this, 'SubZone', {
  zoneName: 'sub.someexample.com',
});

// import the delegation role by constructing the roleArn
const delegationRoleArn = Stack.of(this).formatArn({
  region: '', // IAM is global in each partition
  service: 'iam',
  account: 'parent-account-id',
  resource: 'role',
  resourceName: 'MyDelegationRole',
});
const delegationRole = iam.Role.fromRoleArn(this, 'DelegationRole', delegationRoleArn);

// create the record
new route53.CrossAccountZoneDelegationRecord(this, 'delegate', {
  delegatedZone: subZone,
  parentHostedZoneName: 'someexample.com', // or you can use parentHostedZoneId
  delegationRole,
});
于 2022-02-14T18:46:01.910 回答
0

截至本答案发布之日,随着 API 的更新,CDK 允许这种类型的 DNS 验证。我已在预先存在的托管区域中成功创建了一个包含子域和多个备用域的证书。但是,我没有使用关联帐户,所以我没有检查这方面是否有效。

在 上DnsValidatedCertificate,输入属性validation可以获取对 的调用的结果CertificateValidation.fromDnsMultiZone。此静态成员调用接受一个对象,其键/值对代表证书中的域及其IHostedZone对象。您可以通过调用 CDK Route53 来获取对托管区域的引用HostedZone.fromLookup(this, id, { domainName: domain })

把它们放在一起:

import { HostedZone } from '@aws-cdk/aws-route53';
import { Certificate, CertificateValidation } from '@aws-cdk/aws-certificatemanager';

// within the stack...
const hzone = HostedZone.fromLookup(this, 'hz', { domainName: 'www.example.com' });
const cert  = new Certificate(this, 'cert', {
  domainName: site,
  validation: CertificateValidation.fromDnsMultiZone({ 'www.example.com': hzone }),
  region: 'us-east-1',
});

注意:您可能需要根据您的 DNS 配置对上述代码片段进行一些调整。例如,www.example.com可以是托管区域内的 CNAME 或 A 记录example.com。在这种情况下,调用fromLookup应该example.com用作domainName代替www子域。

此外,此过程会创建一个文件cdk.context.json,为您的托管区域引用保留 DNS 查找上下文。这是一个关于需要将此文件签入源代码管理的完整讨论线程。

于 2021-06-14T07:12:21.033 回答