Closed RekhaPGE closed 3 years ago
Hello @RekhaRavula, you need to provide a DomainValidationOptions for your domain. See the example here. Can you post the full resource from the template?
@dflook,
Please find the below resource from our template, we are trying to use secondary domain name xyz.nonprod.pqr.com (e.x) using
generatedCertificate:
Properties:
DomainName: !Ref pWebsiteFQDN
DomainValidationOptions:
- DomainName: !Ref pWebsiteFQDN
HostedZoneId: !Ref pHostedZoneId
Route53RoleArn: !Ref pRoute53AssumedRoleArn
SubjectAlternativeNames:
- xyz.nonprod.pqr.com
Tags:
- Key: AppID
Value: !Ref pAppID
- Key: Environment
Value: !Ref pEnv
- Key: Notify
Value: !Ref pNotify
- Key: Order
Value: !Ref pOrderNumber
- Key: Org
Value: !Ref pOrg
- Key: AppName
Value: !Ref pAppName
- Key: Owner
Value: !Ref pCFNOwnerTag
- Key: Compliance
Value: None
- Key: DataClassification
Value: Confidential
- Key: CRIS
Value: N/A
- Key: MCP
Value: "noMcp"
ValidationMethod: DNS
Region: us-east-1
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
But Lambda throwing the below error:
[ERROR] 2021-07-09T02:10:27.28Z 40256572-6e9e-4696-9d58-a7ad516354df
Traceback (most recent call last):
File "/var/task/index.py", line 93, in handler
if K not in e:g()
File "/var/task/index.py", line 23, in g
for H in set([A[M]]+A.get('SubjectAlternativeNames',[])):k(H)
File "/var/task/index.py", line 70, in k
raise U(N+' missing for '+n)
RuntimeError: DomainValidationOptions missing for xyz.nonprod.pqr.com
Note: What I'm suspecting is Lambda is unable to read DomainValidationOptions for secondary domain which we are trying to add through SubjectAlternativeNames
SubjectAlternativeNames names should not be inside DomainValidationOptions - is that a copy paste error?
You will need a DomainValidationOptions zone for all zones needed - both the DomainName zone and the zone for any SubjectAlternativeNames (if different).
So it would look something like:
generatedCertificate:
Properties:
DomainName: !Ref pWebsiteFQDN
SubjectAlternativeNames:
- xyz.nonprod.pqr.com
DomainValidationOptions:
- DomainName: !Ref pWebsiteFQDN
HostedZoneId: !Ref pHostedZoneId
Route53RoleArn: !Ref pRoute53AssumedRoleArn
- DomainName: nonprod.pqr.com
HostedZoneId: !Ref NonprodZoneId
Route53RoleArn: !Ref pRoute53AssumedRoleArn
ValidationMethod: DNS
Region: us-east-1
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
As per your suggestion, I used the same code you mentioned above but still getting the same error, can you please confirm in your test environment were you able to add the secondary domain (SubjectAlternativeNames) to your certificate. I think Lambda code is not able to validate the secondary domain and going to exception in the below code:
def k(n):
C='.';n=n.rstrip(C);D={A[p].rstrip(C):A for A in B[N]};A=n.split(C)
while len(A):
if C.join(A)in D:return D[C.join(A)]
A=A[1:]
raise T(N+' missing'+' for '+n)
The Exception is telling you something. Please examine and check your resource is correct.
Two domains are in the same AWS account, one is getting updated correctly but secondary domain is failing at validation level. Our resource is correct.
@RekhaRavula Can you post the actual resource you are using
Please find below:
Resources:
CustomAcmCertificateLambda:
Metadata:
Source: https://github.com/dflook/cloudformation-dns-certificate
Version: 1.7.3
Properties:
Code:
ZipFile: "x=Exception\nV=True\nU=RuntimeError\nimport copy,hashlib as s,json,logging\
\ as B,time\nfrom boto3 import client as J\nfrom botocore.exceptions import\
\ ClientError as t,ParamValidationError as u\nfrom urllib.request import\
\ Request as v,urlopen as w\nA=B.getLogger()\nA.setLevel(B.INFO)\nC=A.info\n\
R=A.exception\nL=copy.copy\nS=time.sleep\nT=lambda j:json.dumps(j,sort_keys=V).encode()\n\
K='R'\ndef handler(e,c):\n\tAA='OldResourceProperties';A9='Update';A8='Delete';A7='None';A6='acm';A5='FAILED';A4='properties';A3='stack-id';A2='logical-id';A1='DNS';r='Old';p='Certificate';q='LogicalResourceId';o='ValidationMethod';n='Route53RoleArn';m='Region';d='RequestType';b='StackId';a=None;Q='Status';P='Key';O='';N='DomainValidationOptions';M='DomainName';I='ResourceProperties';H='cloudformation:';G='Value';F='CertificateArn';E='Tags';B='PhysicalResourceId';f=c.get_remaining_time_in_millis;C(e)\n\
\tdef g():\n\t\tC=L(A)\n\t\tfor G in ['ServiceToken',m,E,n]:C.pop(G,a)\n\
\t\tif o in A:\n\t\t\tif A[o]==A1:\n\t\t\t\tfor H in set([A[M]]+A.get('SubjectAlternativeNames',[])):k(H)\n\
\t\t\t\tdel C[N]\n\t\te[B]=D.request_certificate(IdempotencyToken=z,**C)[F];l()\n\
\tdef W(a):\n\t\twhile V:\n\t\t\ttry:D.delete_certificate(**{F:a});return\n\
\t\t\texcept t as B:\n\t\t\t\tR(O);A=B.response['Error']['Code']\n\t\t\t\
\tif A=='ResourceInUseException':\n\t\t\t\t\tif f()/1000<30:raise\n\t\t\t\
\t\tS(5);continue\n\t\t\t\tif A in['ResourceNotFoundException','ValidationException']:return\n\
\t\t\t\traise\n\t\t\texcept u:return\n\tdef X(p):\n\t\tfor I in D.get_paginator('list_certificates').paginate():\n\
\t\t\tfor A in I['CertificateSummaryList']:\n\t\t\t\tC(A)\n\t\t\t\tif p[M].lower()==A[M]:\n\
\t\t\t\t\tB={B[P]:B[G]for B in D.list_tags_for_certificate(**{F:A[F]})[E]}\n\
\t\t\t\t\tif B.get(H+A2)==e[q]and B.get(H+A3)==e[b]and B.get(H+A4)==Y(p):return\
\ A[F]\n\tdef h():\n\t\tif K in e:raise U('Certificate not issued in time')\n\
\t\te[K]=K;C(e);J('lambda').invoke(FunctionName=c.invoked_function_arn,InvocationType='Event',Payload=T(e))\n\
\tdef i():\n\t\twhile f()/1000>30:\n\t\t\tA=D.describe_certificate(**{F:e[B]})[p];C(A)\n\
\t\t\tif A[Q]=='ISSUED':return V\n\t\t\telif A[Q]==A5:raise U(A.get('FailureReason',O))\n\
\t\t\tS(5)\n\t\treturn False\n\tdef y():A=L(e[r+I]);A.pop(E,a);B=L(e[I]);B.pop(E,a);return\
\ A!=B\n\tdef j():\n\t\tX='Type';W='Name';U='HostedZoneId';T='ValidationStatus';R='PENDING_VALIDATION';K='ResourceRecord'\n\
\t\tif A.get(o)!=A1:return\n\t\twhile V:\n\t\t\tH=D.describe_certificate(**{F:e[B]})[p];C(H)\n\
\t\t\tif H[Q]!=R:return\n\t\t\tif not[A for A in H.get(N,[{}])if T not in\
\ A or K not in A]:break\n\t\t\tS(1)\n\t\tfor E in H[N]:\n\t\t\tif E[T]==R:L=k(E[M]);O=L.get(n,A.get(n));I=J('sts').assume_role(RoleArn=O,RoleSessionName=(p+e[q])[:64],DurationSeconds=900)['Credentials']if\
\ O is not a else{};P=J('route53',aws_access_key_id=I.get('AccessKeyId'),aws_secret_access_key=I.get('SecretAccessKey'),aws_session_token=I.get('SessionToken')).change_resource_record_sets(**{U:L[U],'ChangeBatch':{'Comment':'Domain\
\ validation for '+e[B],'Changes':[{'Action':'UPSERT','ResourceRecordSet':{W:E[K][W],X:E[K][X],'TTL':60,'ResourceRecords':[{G:E[K][G]}]}}]}});C(P)\n\
\tdef k(n):\n\t\tC='.';n=n.rstrip(C);D={B[M].rstrip(C):B for B in A[N]};B=n.split(C)\n\
\t\twhile len(B):\n\t\t\tif C.join(B)in D:return D[C.join(B)]\n\t\t\tB=B[1:]\n\
\t\traise U(N+' missing for '+n)\n\tY=lambda v:s.new('md5',T(v)).hexdigest()\n\
\tdef l():A=L(e[I].get(E,[]));A+=[{P:H+A2,G:e[q]},{P:H+A3,G:e[b]},{P:H+'stack-name',G:e[b].split('/')[1]},{P:H+A4,G:Y(e[I])}];D.add_tags_to_certificate(**{F:e[B],E:A})\n\
\tdef Z():\n\t\tC(e);A=w(v(e['ResponseURL'],T(e),{'content-type':O},method='PUT'))\n\
\t\tif A.status!=200:raise x(A)\n\ttry:\n\t\tz=Y(e['RequestId']+e[b]);A=e[I];D=J(A6,region_name=A.get(m));e[Q]='SUCCESS'\n\
\t\tif e[d]=='Create':\n\t\t\tif K not in e:e[B]=A7;g()\n\t\t\tj()\n\t\t\
\tif not i():return h()\n\t\telif e[d]==A8:\n\t\t\tif e[B]!=A7:\n\t\t\t\t\
if e[B].startswith('arn:'):W(e[B])\n\t\t\t\telse:W(X(A))\n\t\telif e[d]==A9:\n\
\t\t\tif y():\n\t\t\t\tC(A9)\n\t\t\t\tif X(A)==e[B]:\n\t\t\t\t\ttry:D=J(A6,region_name=e[AA].get(m));C(A8);W(X(e[AA]))\n\
\t\t\t\t\texcept:R(O)\n\t\t\t\t\treturn Z()\n\t\t\t\tif K not in e:g()\n\
\t\t\t\tj()\n\t\t\t\tif not i():return h()\n\t\t\telse:\n\t\t\t\tif E in\
\ e[r+I]:D.remove_tags_from_certificate(**{F:e[B],E:e[r+I][E]})\n\t\t\t\t\
l()\n\t\telse:raise U(e[d])\n\t\treturn Z()\n\texcept x as A0:R(O);e[Q]=A5;e['Reason']=str(A0);return\
\ Z()"
Description: Cloudformation custom resource for DNS validated certificates
Handler: index.handler
Role: !GetAtt 'CustomAcmCertificateLambdaExecutionRole.Arn'
Runtime: python3.6
Timeout: 900
Tags:
- Key: AppID
Value: !Ref pAppID
- Key: Environment
Value: !Ref pEnv
- Key: Notify
Value: !Ref pNotify
- Key: Order
Value: !Ref pOrderNumber
- Key: Org
Value: !Ref pOrg
- Key: AppName
Value: !Ref pAppName
- Key: Owner
Value: !Ref pCFNOwnerTag
- Key: Compliance
Value: None
- Key: DataClassification
Value: Confidential
- Key: CRIS
Value: N/A
- Key: MCP
Value: "noMcp"
Type: AWS::Lambda::Function
CustomAcmCertificateLambdaExecutionRole:
Properties:
Tags:
- Key: AppID
Value: !Ref pAppID
- Key: Environment
Value: !Ref pEnv
- Key: Notify
Value: !Ref pNotify
- Key: Order
Value: !Ref pOrderNumber
- Key: Org
Value: !Ref pOrg
- Key: AppName
Value: !Ref pAppName
- Key: Owner
Value: !Ref pCFNOwnerTag
- Key: Compliance
Value: None
- Key: DataClassification
Value: Confidential
- Key: CRIS
Value: N/A
- Key: MCP
Value: "noMcp"
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/service-role/AWSLambdaRole
Policies:
- PolicyDocument:
Statement:
- Action:
- acm:AddTagsToCertificate
- acm:DeleteCertificate
- acm:DescribeCertificate
- acm:RemoveTagsFromCertificate
Effect: Allow
Resource:
- !Sub 'arn:aws:acm:*:${AWS::AccountId}:certificate/*'
- Action:
- acm:RequestCertificate
- acm:ListTagsForCertificate
- acm:ListCertificates
Effect: Allow
Resource:
- '*'
- Action:
- route53:ChangeResourceRecordSets
Effect: Allow
Resource:
- arn:aws:route53:::hostedzone/*
- Action:
- sts:AssumeRole
Resource:
- !Ref pRoute53AssumedRoleArn
Effect: Allow
Version: '2012-10-17'
PolicyName: !Sub '${AWS::StackName}CustomAcmCertificateLambdaExecutionPolicy'
Type: AWS::IAM::Role
generatedCertificate:
Properties:
DomainName: !Ref pWebsiteFQDN
SubjectAlternativeNames:
- geomartcloud-qa.nonprod.pge.com
DomainValidationOptions:
- DomainName: !Ref pWebsiteFQDN
HostedZoneId: !Ref pHostedZoneId
Route53RoleArn: !Ref pRoute53AssumedRoleArn
- DomainName: !Ref pWebsiteFQDN1
HostedZoneId: !Ref pHostedZoneId
Route53RoleArn: !Ref pRoute53AssumedRoleArn
Tags:
- Key: AppID
Value: !Ref pAppID
- Key: Environment
Value: !Ref pEnv
- Key: Notify
Value: !Ref pNotify
- Key: Order
Value: !Ref pOrderNumber
- Key: Org
Value: !Ref pOrg
- Key: AppName
Value: !Ref pAppName
- Key: Owner
Value: !Ref pCFNOwnerTag
- Key: Compliance
Value: None
- Key: DataClassification
Value: Confidential
- Key: CRIS
Value: N/A
- Key: MCP
Value: "noMcp"
ValidationMethod: DNS
Region: us-east-1
ServiceToken: !GetAtt 'CustomAcmCertificateLambda.Arn'
Type: Custom::DNSCertificate
What is pWebsiteFQDN
and pWebsiteFQDN1
set to?
pWebsiteFQDN and pWebsiteFQDN1 are set to hawctst.nonprod.pge.com and geomartcloud-tst.nonprod.pge.com respectively.
You have DomainValidationOptions for zones hawctst.nonprod.pge.com
and geomartcloud-tst.nonprod.pge.com
, but not one for geomartcloud-qa.nonprod.pge.com
. The error is telling you that there should be a DomainValidationOptions
for geomartcloud-qa.nonprod.pge.com
, but it is missing.
@dflook , looks like there is typo. I think it would be better if I can give more information during troubleshooting session. Can you please kindly let me know which time works for you. Thank you.
@RekhaRavula for commercial support queries please contact me via email at daniel@flook.org
Hi,
I am trying to add SubjectAlternativeNames to add additional domain (e.g..additional.example.com) I am following this syntax: Properties: SubjectAlternativeNames:
But CFT throwing the below error: Received response status [FAILED] from custom resource. Message returned: DomainValidationOptions missing for additional.example.com (RequestId: 9758388c-7dba-4c2a-a15b-bfa8f06a0931)
Can you please let me know why Lambda is sending FAILED status to CFT and kindly provide the update.
Regards, Rekha