如何设置HostedZone,以便将其委托给另一个AWS账户中的父DNS记录? [英] How can I set up my HostedZone so that it delegates to a parent DNS record in another AWS account?

查看:67
本文介绍了如何设置HostedZone,以便将其委托给另一个AWS账户中的父DNS记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用CDK创建API网关和Lambda的TypeScript代码.它可以工作并部署到标准AWS URL.到目前为止一切顺利.

I have some TypeScript code that uses CDK to create an API Gateway and a Lambda. It works and deploys to a standard AWS URL. So far so good.

我现在需要传输API网关,以便它可以在自定义域上运行,以便可以在Web应用程序中设置Cookie.事实证明,这要困难得多,而且我怀疑我遇到了困难,因为我同时是TypeScript,AWS和CDK的新手.网络上有很多文档资源,但是大多数文档资源要求我重写我拥有的宝贵的少量工作代码,我不愿意这样做.

I now need to transfer the API Gateway so that it operates on a custom domain, so that it can set a cookie in a web app. This is proving far harder, and I suspect I am having difficulty because I am new to TypeScript, AWS, and CDK all at the same time. There are a number of documentation resources on the web, but most would require me to rewrite the precious little working code I have, which I am reluctant to do.

我手动创建了一个证书,因为这需要验证,因此在代码中创建它是没有意义的.除此之外,我希望所有其他资源由堆栈中的CDK代码创建.在我看来,如果我必须手动配置,它将无法达到CDK的目的.

I have created a certificate manually, because that requires validation and thus it does not make sense to create it in code. Other than that I want all other resources to be created by CDK code in a Stack. In my view, it defeats the purpose of CDK if I have to configure things manually.

下面的代码将我需要的所有内容部署到 gatekeeper.d.aws.example.com -一个HostedZone,一个ARecord,一个LambdaRestApi和一个Function(lambda).但是,它不起作用,因为新分配给 gatekeeper.d.aws.example.com 的NS记录与父 d.aws.example.com 中的记录不匹配

The below code deploys everything I need to gatekeeper.d.aws.example.com - a HostedZone, an ARecord, a LambdaRestApi and a Function (lambda). However it does not work because the NS records newly assigned to gatekeeper.d.aws.example.com do not match the ones in the parent d.aws.example.com.

我认为这意味着,尽管 d.aws.example.com 是已知的",但 gateway 子域无法将其委派给它.

I think this means that although d.aws.example.com is "known", the gateway subdomain cannot delegate to it.

这是我的工作代码:

// Create the lambda resource
const referrerLambda = new lambda.Function(this, 'EisReferrerLambda', {
    runtime: lambda.Runtime.NODEJS_14_X,
    handler: 'index.handler',
    code: lambda.Code.fromAsset(path.join(__dirname, '../../src/lambda')),
    environment: env
});

// Set up the domain name on which the API should appear
const domainName = 'gatekeeper.d.aws.example.com';

// TODO need to fetch it with an env var? Or read from environment?
const certificateArn = 'arn:aws:acm:us-east-1:xxx:certificate/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy';

const certificate = acm.Certificate.fromCertificateArn(this, 'SslCertificate', certificateArn);

const hostedZone = new route53.HostedZone(this, 'EisReferrerHostedZone', {
    zoneName: domainName
});

// Add an A record
new route53.ARecord(this, 'DnsRecord', {
    zone: hostedZone,
    target: route53.RecordTarget.fromAlias(new targets.ApiGateway(apiGateway)),
});

// I think I need a DomainNameOptions object
const dno : DomainNameOptions = { certificate, domainName };

// Create the APIG resource
// See https://intro-to-cdk.workshop.aws/the-workshop/4-create-apigateway.html
const apiGateway = new apigw.LambdaRestApi(this, "EisReferrerApi", {
    handler: referrerLambda,
    // proxy = on means that the lambda handles all requests to the APIG,
    // instead of just explicit resource endpoints
    proxy: false,
    // deploy = on means that we get a default stage of "prod", I don't want
    // that - I'm creating a custom Deployment anyway
    deploy: false,
    // Point to a domain name options object
    domainName: dno
});

// Create an endpoint in the APIG
// https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigateway-readme.html#defining-apis
const items = apiGateway.root.addResource('gatekeeper');
items.addMethod('GET');  // GET /default/gatekeeper

// The deployment resource is just needed by the Stage system
const deployment = new apigw.Deployment(
    this,
    'EisReferrerDeployment',
    { api: apiGateway }
);

// Create a Stage (this affects the first component in the path
const stageName = 'default';
apiGateway.deploymentStage = new apigw.Stage(
    this,
    stageName,
    { deployment, stageName }
);

问题

从代码中可以看到,我已经找到了如何创建A记录的方法,但是创建/修改NS记录似乎更困难.首先,似乎没有NSRecord类,至少基于从我的IDE自动完成中探索类结构的基础上.

Question

As you can see from the code, I've found how to create an A record, but creating/modifying NS records seems harder. For a start, there does not seem to be an NSRecord class, at least based on exploring the class structure from my IDE autocomplete.

一个基本的解决方案将允许我创建具有在其他地方(拥有"该域的AWS账户中)设置的固定值的NS记录.更好的解决方案是先读取这些记录,然后再使用它们.

A rudimentary solution would allow me to create NS records with the fixed values that are set up elsewhere (in the AWS account that "owns" the domain). A better solution would be to read what those records are, and then use them.

要查看我的想法是否正确,我运行了此部署代码,并在HostedZone中手动修改了自动分配的NS记录,以使其与父帐户(在另一个帐户中)的记录匹配.我认为我必须等待此更改渗透到DNS系统中,然后我将更新结果.

To see if my thinking is on the right track, I have run this deployment code, and manually modified the automatically assigned NS records in the HostedZone to match the records in the parent (in the other account). I think I have to wait for this change to seep into the DNS system, and I will update with the result.

我的手动调整不起作用.因此,我找到了新尝试做的事情(请参阅将NS记录添加到其他帐户中的HostedZone中"):

My manual adjustment did not work. I have therefore found a new thing to try (see "To add a NS record to a HostedZone in different account"):

// Commented out from earlier code
// const hostedZone = new route53.HostedZone(this, 'EisReferrerHostedZone', {
//     zoneName: domainName
// });

// In the account containing the HostedZone
const parentZone = new route53.PublicHostedZone(this, 'HostedZone', {
    zoneName: 'd.aws.example.com',
    crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('12345678012')
});

// In this account
const subZone = new route53.PublicHostedZone(this, 'SubZone', {
    zoneName: domainName
});

new route53.CrossAccountZoneDelegationRecord(this, 'delegate', {
    delegatedZone: subZone,
    parentHostedZoneId: parentZone.hostedZoneId,
    delegationRole: parentZone.crossAccountDelegationRole
});

这完全满足我的需要,但我担心AWS文档在这里过时了- crossAccountDelegationRole 在我的IDE中呈现为红色,并且由于 cdk时未定义而崩溃diff 运行.

This sounds exactly what I need, but I fear the AWS documentation is out of date here - crossAccountDelegationRole is rendered in red in my IDE, and it crashes due to being undefined when cdk diff is run.

我假设上述属性是拼写错误或对库的过时版本的引用.我现在正在这样做:

I am assuming the property mentioned above is a typo or a reference to an outdated version of the library. I am now doing this:

new route53.CrossAccountZoneDelegationRecord(this, 'delegate', {
    delegatedZone: subZone,
    parentHostedZoneId: parentZone.hostedZoneId,
    delegationRole: parentZone.crossAccountZoneDelegationRole
});

这种感觉非常接近,但崩溃了:

This feel tantalisingly close, but it crashes:

无法创建资源.AccessDenied:用户:arn:aws:sts :: xxxxxxxxxxxx:assumed-role/CustomCrossAccountZoneDelegationC-xxx无权执行在资源上执行:sts:AssumeRole:arn:aws:iam :: yyyyyyyyyyyy:role/HostedZoneCrossAccountZoneDelegat-yyy

Failed to create resource. AccessDenied: User: arn:aws:sts::xxxxxxxxxxxx:assumed-role/CustomCrossAccountZoneDelegationC-xxx is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::yyyyyyyyyyyy:role/HostedZoneCrossAccountZoneDelegat-yyy

我想知道是否需要声明其他帐户的IAM信用吗?我有它们.

I wonder if I need to declare the IAM creds for the other account? I do have them.

无论如何,我不确定为什么需要权限-它不能只读取另一个帐户中的NS记录并将它们复制到本地帐户吗?无论如何,另一个帐户中的DNS是公开的.

I am not sure why permissions are needed, anyway - could it not just read the NS records in the other account and copy them to the local account? The DNS in the other account is public anyway.

我愿意研究解决IAM错误的方法,但这并不像在黑暗中拍摄那样.我可能还要花两个小时来解决这个子问题,却发现整个事情由于另一个原因而失败.

I am willing to research fixing the IAM error, but this doesn't half feel like shooting in the dark. I might spend another two hours inching towards solving that sub-problem, only to find that the whole thing will fail for another reason.

我已经创建了一个角色"在远程帐户中提供"AmazonRoute53FullAccess";烫发到我针对CDK部署的目标帐户.但是,我仍然收到AccessDenied错误.我想知道是否需要以某种方式显式调用该远程角色.我该怎么办?

I have created a "Role" in the remote account to give "AmazonRoute53FullAccess" perms to the account that I am targetting for CDK deployment. However I still get the AccessDenied error. I wonder if I need to explicitly invoke that remote role in some fashion; how can I do that?

推荐答案

今天试图做同样的事情&您的帖子让我成功了90%,谢谢!我最终将其与其他IAM负责人(组织)一起使用,这对我的用例来说是可以的.

Was trying to do the same thing today & your post got me 90% of the way there, thanks! I ended up getting it to work with a different IAM principal (Organization) which was ok for my use case.

crossAccountZoneDelegationPrincipal可以访问托管子区域的帐户,以访问您的根区域并写入子区域的委派(NS)记录.

The crossAccountZoneDelegationPrincipal gives access to accounts hosting subzones, to access your root zone and write delegation (NS) records for the subzones.

对于我的用例,所有帐户都位于同一组织内,因此我创建了这样的根区域->

For my use case, all the accounts resided within the same organization, so I created my root zone like this ->

const rootZone = new route53.PublicHostedZone(this, 'rootZone', {
      zoneName: `root.zone`,
      crossAccountZoneDelegationPrincipal: new iam.OrganizationPrincipal('o-####')
    });

这将使用以下策略设置IAM角色;

This sets up an IAM role with the following policy;

    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "route53:ChangeResourceRecordSets",
            "Resource": "arn:aws:route53:::hostedzone/#####",
            "Effect": "Allow"
        }
    ]
}

以及以下信任策略;

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalOrgID": "o-####"
        }
      }
    }
  ]
}

有效地允许具有该OrgID的任何人在根区域中写入记录.

Which effectively allows anyone with that OrgID to write records in the root zone.

在我的分区中,我使用它;

In my subzones, I run with this;

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

const delegationRole = iam.Role.fromRoleArn(this, 'delegationRole', 'arn:aws:iam::###:role/###')

    new route53.CrossAccountZoneDelegationRecord(this, 'delegate', {
      delegatedZone: subZone,
      parentHostedZoneId: '###',
      delegationRole: delegationRole
    });

这最终在根区域为我的子区域创建了委托记录.如果组织负责人不适合您的用例,并且您仍然需要授予多个帐户该权限,请尝试使用复合负责人

This ended up creating the delegation records in the root zone, for my subzone. If the organization principal doesn't fit your use case and you still need to grant multiple accounts that authority, try the composite principal https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iam.CompositePrincipal.html

还想解决在另一个答案中提出的关注,即它是反模式&.跨帐户CDK很难.这实际上不是跨帐户CDK.这是利用AWS提供的模式(特别是拉动lambda来执行根区域中子区域记录的置备).

Also wanted to address the concerns raised in the other answer around it being an anti-pattern & cross-account CDK being hard. This isn't really cross account CDK. This is utilizing a pattern provided by AWS (specifically spinning up a lambda to execute the provisioning of subzone records in a root zone).

希望它对您有用!

这篇关于如何设置HostedZone,以便将其委托给另一个AWS账户中的父DNS记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆