├── .gitignore ├── images ├── AWSOrg-Option1.png └── AWSOrg-Option2.png ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── testConsumerRole.json ├── LICENSE ├── testStack-NoCRL.json ├── testStackL0.json ├── testStack-NoLogBucket.json ├── testStackL1.json ├── testStackL2.json ├── testStackL3.json ├── testStackL4-noShare.json ├── testStackL4-orgShare.json ├── testStackL4.json ├── CONTRIBUTING.md ├── AWSPCA-CertConsumerRole.yaml ├── epics.md ├── README.md └── AWSPCA-RootCASubCA.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /images/AWSOrg-Option1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/acmpca-hierarchy/main/images/AWSOrg-Option1.png -------------------------------------------------------------------------------- /images/AWSOrg-Option2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/acmpca-hierarchy/main/images/AWSOrg-Option2.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGE LOG 2 | * V 1.1 - Re-branding from AWS Certificate Manager (ACM) Private CA (PCA) to AWS Private Certificate Authority (AWS Private CA) 3 | * V 1.0 - First release -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /testConsumerRole.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pPCAConsumerRoleName", 4 | "ParameterValue": "CertificateConsumer" 5 | }, 6 | { 7 | "ParameterKey": "pPCAConsumerPermissionsBoundary", 8 | "ParameterValue": "" 9 | }, 10 | { 11 | "ParameterKey": "pPCAConsumerAccounts", 12 | "ParameterValue": "57xxxxxxxx89,97xxxxxxxx72" 13 | }, 14 | { 15 | "ParameterKey": "pPCAExternalId", 16 | "ParameterValue": "PCARole123" 17 | } 18 | ] 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /testStack-NoCRL.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "nocrl-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.nocrl-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL0.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "l0-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "mydomain-io-awspca-log-l0" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "mydomain-io-awspca-crl-l0" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStack-NoLogBucket.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "nolog-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.nolog-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "mydomain-io-awspca-crl-l5" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "l1-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.l1-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "mydomain-io-awspca-log-l1" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "mydomain-io-awspca-crl-l1" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "l2-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.l2-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "subdomain2.subdomain1.l2-mydomain.io" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "mydomain-io-awspca-log-l2" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "mydomain-io-awspca-crl-l2" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "l3-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.l3-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "subdomain2.subdomain1.l3-mydomain.io" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "subdomain3.subdomain2.subdomain1.l3-mydomain.io" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "mydomain-io-awspca-log-l3" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "mydomain-io-awspca-crl-l3" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL4-noShare.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "noshare-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.noshare-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "subdomain2.subdomain1.noshare-mydomain.io" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "subdomain3.subdomain2.subdomain1.noshare-mydomain.io" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "subdomain4.subdomain3.subdomain2.subdomain1.noshare-mydomain.io" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL4-orgShare.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "orgshare-mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.orgshare-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "subdomain2.subdomain1.orgshare-mydomain.io" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "subdomain3.subdomain2.subdomain1.orgshare-mydomain.io" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "subdomain4.subdomain3.subdomain2.subdomain1.orgshare-mydomain.io" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /testStackL4.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrganization", 4 | "ParameterValue": "MyDomain LLC" 5 | }, 6 | { 7 | "ParameterKey": "pOrganizationalUnit", 8 | "ParameterValue": "Cloud IT" 9 | }, 10 | { 11 | "ParameterKey": "pCountry", 12 | "ParameterValue": "US" 13 | }, 14 | { 15 | "ParameterKey": "pState", 16 | "ParameterValue": "California" 17 | }, 18 | { 19 | "ParameterKey": "pLocality", 20 | "ParameterValue": "Los Angeles" 21 | }, 22 | { 23 | "ParameterKey": "pRootCommonName", 24 | "ParameterValue": "mydomain.io" 25 | }, 26 | { 27 | "ParameterKey": "pSub1CommonName", 28 | "ParameterValue": "subdomain1.l4-mydomain.io" 29 | }, 30 | { 31 | "ParameterKey": "pSub2CommonName", 32 | "ParameterValue": "subdomain2.subdomain1.l4-mydomain.io" 33 | }, 34 | { 35 | "ParameterKey": "pSub3CommonName", 36 | "ParameterValue": "subdomain3.subdomain2.subdomain1.l4-mydomain.io" 37 | }, 38 | { 39 | "ParameterKey": "pSub4CommonName", 40 | "ParameterValue": "subdomain4.subdomain3.subdomain2.subdomain1.l4-mydomain.io" 41 | }, 42 | { 43 | "ParameterKey": "pLogCRLBucket", 44 | "ParameterValue": "mydomain-io-awspca-log-l4" 45 | }, 46 | { 47 | "ParameterKey": "pRootCRLBucket", 48 | "ParameterValue": "mydomain-io-awspca-crl-l4" 49 | }, 50 | { 51 | "ParameterKey": "pManagmentAccount", 52 | "ParameterValue": "1111222233334444" 53 | }, 54 | { 55 | "ParameterKey": "pAWSOrganizationId", 56 | "ParameterValue": "o-fortestorg" 57 | }, 58 | { 59 | "ParameterKey": "pAWSOrganizationalUnit", 60 | "ParameterValue": "ou-foratestou" 61 | }, 62 | { 63 | "ParameterKey": "pPCAAdminRoleName", 64 | "ParameterValue": "PrivateCAAdmin" 65 | }, 66 | { 67 | "ParameterKey": "pPCAAdminPermissionsBoundary", 68 | "ParameterValue": "" 69 | }, 70 | { 71 | "ParameterKey": "pPCAAdminAccounts", 72 | "ParameterValue": "5555666677778888" 73 | }, 74 | { 75 | "ParameterKey": "pPCAExternalId", 76 | "ParameterValue": "ExternalPCARole" 77 | } 78 | ] 79 | 80 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /AWSPCA-CertConsumerRole.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | pPCAConsumerRoleName: 3 | Description: Name of the Private CA Consumer role. Leave blank to skip this role. 4 | Default: "PCAConsumer" 5 | Type: String 6 | pPCAConsumerPermissionsBoundary: 7 | Description: Permissions Boundary ARN for PCA Consumer, this policy must be pre-defined. Leave blank to skip the permissions boundary. AWS best practices recommends using a permissions boundary. 8 | Type: String 9 | Default: "" 10 | pPCAConsumerAccounts: 11 | Description: Comma separated list of AWS Account numbers for the principal that assumes the Private CA Consumer role. Leave blank to use the local PCA account only in the trust policy. 12 | Type: CommaDelimitedList 13 | Default: "" 14 | pPCAExternalId: 15 | Description: External ID to be used when assuming the roles, e.g. ExternalPCARole. Leave blank to use the local PCA account only. AWS best practices suggests using an external ID with cross-account roles. 16 | Type: String 17 | Default: "" 18 | 19 | Metadata: 20 | AWS::CloudFormation::Interface: 21 | ParameterGroups: 22 | - Label: 23 | default: "IAM Roles" 24 | Parameters: 25 | - pPCAConsumerRoleName 26 | - pPCAConsumerPermissionsBoundary 27 | - pPCAConsumerAccounts 28 | - pPCAExternalId 29 | # Define user friendly names for the parameters 30 | ParameterLabels: 31 | pPCAConsumerRoleName: 32 | default: Private CA Consumer Role Name 33 | pPCAConsumerPermissionsBoundary: 34 | default: Private CA Consumer Permissions Boundary 35 | pPCAConsumerAccounts: 36 | default: Private CA Consumer Accounts 37 | pPCAExternalId: 38 | default: Private CA External ID 39 | 40 | Conditions: 41 | CreatePCAConsumerRole: !Not 42 | - !Equals 43 | - !Ref pPCAConsumerRoleName 44 | - "" 45 | CreatePCAConsumerRoleWithBoundary: !Not 46 | - !Equals 47 | - !Ref pPCAConsumerPermissionsBoundary 48 | - "" 49 | UseLocalPCAAccountForConsumer: !Equals 50 | - !Join ["", !Ref pPCAConsumerAccounts] 51 | - "" 52 | # No need for an external ID if not using a cross-account role 53 | UseExternalId: !And 54 | - !Not 55 | - !Condition UseLocalPCAAccountForConsumer 56 | - !Not 57 | - !Equals 58 | - !Ref pPCAExternalId 59 | - "" 60 | 61 | Resources: 62 | rPCAConsumerRole: 63 | UpdateReplacePolicy: "Delete" 64 | Type: "AWS::IAM::Role" 65 | Condition: CreatePCAConsumerRole 66 | DeletionPolicy: "Delete" 67 | Properties: 68 | RoleName: !Ref pPCAConsumerRoleName 69 | Description: "Private CA consumer role" 70 | AssumeRolePolicyDocument: 71 | Statement: 72 | - Effect: Allow 73 | Action: sts:AssumeRole 74 | Principal: !If 75 | - UseLocalPCAAccountForConsumer 76 | - AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" 77 | - AWS: !Ref pPCAConsumerAccounts 78 | Condition: !If 79 | - UseExternalId 80 | - StringEquals: 81 | "sts:ExternalId": !Ref pPCAExternalId 82 | - !Ref "AWS::NoValue" 83 | ManagedPolicyArns: 84 | - arn:aws:iam::aws:policy/AWSPrivateCAUser 85 | Policies: 86 | - PolicyName: "ConsumeCertificates" 87 | PolicyDocument: 88 | Version: "2012-10-17" 89 | Statement: 90 | - Sid: "ConsumeCertificates" 91 | Effect: "Allow" 92 | Action: 93 | - "acm:AddTagsToCertificate" 94 | - "acm:DeleteCertificate" 95 | - "acm:DescribeCertificate" 96 | - "acm:ExportCertificate" 97 | - "acm:GetAccountConfiguration" 98 | - "acm:GetCertificate" 99 | - "acm:ImportCertificate" 100 | - "acm:ListCertificates" 101 | - "acm:ListTags" 102 | - "acm:RemoveTagsFromCertificate" 103 | - "acm:RenewCertificate" 104 | - "acm:RequestCertificate" 105 | - "acm:RestoreCertificate" 106 | - "acm:RevokeCertificate" 107 | - "acm:UpdateCertificateOptions" 108 | Resource: "*" 109 | PermissionsBoundary: !If 110 | - CreatePCAConsumerRoleWithBoundary 111 | - !Ref pPCAConsumerPermissionsBoundary 112 | - !Ref "AWS::NoValue" 113 | Path: "/" 114 | Tags: 115 | - Key: "Purpose" 116 | Value: "Consumer role for Private CA" 117 | 118 | Outputs: 119 | oPCAConsumerRole: 120 | Condition: CreatePCAConsumerRole 121 | Value: !GetAtt rPCAConsumerRole.Arn -------------------------------------------------------------------------------- /epics.md: -------------------------------------------------------------------------------- 1 | # Epics 2 | 3 | ## Architect the CA hierarchy 4 | | **Story** | **Description** | **Skills required** | 5 | |--|--|--| 6 | | Collect certificate subject information | Gather certificate subject information about the certificate owner: organization name, organization unit, country, state, locality, and common name. | Cloud architect, Security architect, PKI engineer | 7 | | Collect optional information about AWS Organizations | If the CA is to be part of an AWS Organizations structure and the CA hierarchy is to be shared inside, collect the management account number, organizations ID, and optionally the organization unit (OU) ID if the CA hierarchy is only to be shared with a specific OU. Also, determine what, if any, accounts or OUs of the AWS Organizations that the CA is to be shared. | Cloud architect, Security architect, PKI engineer | 8 | | Design the CA hierarchy | Determine which account will house the root and subordinate CAs. Determine how many subordinate levels the hierarchy requires between the root and the end-entity certificates. See [Designing a CA hierarchy](https://docs.aws.amazon.com/acm-pca/latest/userguide/ca-hierarchy.html) for more information. | Cloud architect, Security architect, PKI engineer | 9 | | Determine naming and tagging conventions for the CA hierarchy | Determine the names for the AWS resources: the root CA and each subordinate CA. Determine what tags should be assigned to each CA. | Cloud architect, Security architect, PKI engineer | 10 | | Determine required encryption and signing algorithms | Determine your organization's encryption algorithm requirements for the public keys that your CA uses when it issues a certificate (default is RSA_2048) and key algorithm that your CA uses for certificate signing (default is SHA256WITHRSA). | Cloud architect, Security architect, PKI engineer | 11 | | Determine certificate revocation requirements for the CA hierarchy | If certificate revocation capabilities are required, establish a naming convention for the S3 bucket containing the certificate revocation list (CRL). | Cloud architect, Security architect, PKI engineer | 12 | | Determine the logging requirements for the CA hierarchy | If access logging capabilities are required, establish a naming convention for the S3 bucket containing the access logs. | Cloud architect, Security architect, PKI engineer | 13 | | Determine certificate expiry periods | Determine expiry for the root signing certificate (default is 10 years), end-entity certificates (default is 13 months), and subordinate signing certificates (defaults to 5 year). Each subordinate should expire earlier than the CAs at higher levels in the hierarchy. For more information, see [Managing the private CA lifecycle](https://docs.aws.amazon.com/acm-pca/latest/userguide/ca-lifecycle.html). | Cloud architect, Security architect, PKI engineer | 14 | 15 | ## Deploy the CA hierarchy 16 | | **Story** | **Description** | **Skills required** | 17 | |--|--|--| 18 | | Fulfill the prequisits for this APG pattern | Consult the Prerequisites for implementing this APG pattern and fulfill each of them. | Cloud administrator, Security engineer, PKI engineer | 19 | | Create CA roles for various personas | Determine the types of AWS Identity & Access Management(AWS IAM) roles or AWS Single Sign-On (AWS SSO) users needed to administrate the various levels of the CA hierarchy, like PrivateCAdmin (provided by the template **AWSPCA-RootCASubCA.yaml**) and CertificateConsumer (see the template **AWSPCA-CertConsumerRole.yaml**). Determine the granularity of policies needed to seperate duties. Create the required AWS IAM roles (or use the ones provided by the template **AWSPCA-RootCASubCA.yaml**) or AWS SSO users in the account that the CA hierarchy resides. | Cloud administrator, Security engineer, PKI engineer | 20 | | Deploy the AWS CloudFormation stack | Choose a deployment method, either AWS Console or AWS CLI. Prepare the list of the template parameters required for this implementation. Create the stack using the AWS CloudFormation template provided by this APG pattern. | Cloud administrator, Security engineer, PKI engineer | 21 | | Architect a solution for updating certificates used by customer managed resources | Resources of integrated AWS services, like Elastic Load Balancing, will update certificates automatically during expiry. However, customer managed resources, like web servers running on EC2 instances, will require another mechanism. Determine what customer managed resources will require end-entity certificates from the private CA. Plan a process to be notified about expiry of customer managed resources and update certificates, see [acm-certificate-expiration-check](https://docs.aws.amazon.com/config/latest/developerguide/acm-certificate-expiration-check.html) for one example using AWS Config and [AWS Certificate Manager now provides certificate expiry monitoring through Amazon CloudWatch](https://aws.amazon.com/about-aws/whats-new/2021/03/aws-certificate-manager-provides-certificate-expiry-monitoring-through-amazon-cloudwatch/) for an example using Amazon CloudWatch and Amazon EventBridge. Write custom scripts to update certificates on customer managed resources and integrate them with triggers to automate the updates. For more information about integrated AWS Services, see [Services integrated with AWS Certificate Manager](https://docs.aws.amazon.com/acm/latest/userguide/acm-services.html). | Cloud administrator, Security engineer, PKI engineer | 22 | 23 | ## Validate and document the CA hierarchy 24 | | **Story** | **Description** | **Skills required** | 25 | |--|--|--| 26 | | Validate optional AWS RAM sharing | If the CA hierarchy is shared with other accounts in an AWS Organizations, login to the AWS Console of one of those accounts, navigate to AWS Private CA, and confirm that the newly created CA is shared to this account. Only the lowest level CA in the hierarchy will be visible as this is the CA that generates the end-entity certificates. Repeat for a sampling of the accounts that the CA is shared with. | Cloud administrator, Security engineer, PKI engineer | 27 | | Validate the CA hierarchy with certificate lifecycle tests | Locate the lifecycle tests provided with this APG pattern. Run the tests that are included to request a certificate, export a certificate, describe a certificate, and delete a certificate from the AWS CLI. | Cloud administrator, Security engineer, PKI engineer | 28 | | Import certificate chain into trust stores | For browsers and other applications to trust a certificate, the certificate’s issuer must be included in the browser’s trust store, which is a list of trusted CAs. Add the certificate chain for the new CA hierarchy to your browser's and application’s trust store. Confirm that the end-entity certificates are trusted. | Cloud administrator, Security engineer, PKI engineer | 29 | | Create a runbook to document the CA hierarchy | Create a runbook document to describe the architecture of the CA hierarchy, the account structure that can request end-entity certificates, the build process, and basic management tasks like end-certificate issuing (unless allowing child account self-service), usage, and tracking. | Cloud administrator, Security engineer, PKI engineer | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Private Certificate Authority (AWS Private CA) shared to AWS Organizations via AWS Resource Access Manager (AWS RAM) 2 | 3 | Large organizations often build a public key infrastructure (PKI) inside the AWS cloud, intended for private use within an organization. With AWS Private Certificate Authority (AWS Private CA), you create your own CA hierarchy and issue certificates with it for authenticating internal users, computers, applications, services, servers, and other devices, and for signing computer code. Certificates issued by a private CA are trusted only within your organization, not on the public internet. 4 | 5 | AWS Resource Access Manager (AWS RAM) allows you to securely share AWS resources within your AWS Organization. Private CA Cross-Account Sharing, gives you the ability to grant permissions for other accounts to use a centralized CA to generate and issue certificates while using the AWS RAM to manage the permissions. This removes the need for a Private CA in every account, saving you money for each CA created, which is a more cost-effective way of deployment. 6 | 7 | See also: 8 | [Designing a CA hierarchy](https://docs.aws.amazon.com/privateca/latest/userguide/ca-hierarchy.html) 9 | [Creating a private CA](https://docs.aws.amazon.com/privateca/latest/userguide/create-CA.html) 10 | [How to use AWS RAM to share your ACM Private CA cross-account](https://aws.amazon.com/blogs/security/how-to-use-aws-ram-to-share-your-acm-private-ca-cross-account/) 11 | [The AWS Prescriptive Guidance for this repository](https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/simplify-private-certificate-management-by-using-aws-private-ca-and-aws-ram.html) 12 | 13 | This solution has following features and benefits: 14 | 15 | - Centralize and simplify management of the private CA hierarchy using AWS Private CA. 16 | - Export certificates and keys to customer managed devices in AWS and on-premises. 17 | - Uses an AWS CloudFormation template for a rapid deployment and consistent provisioning experience. 18 | - Create a private root CA along with either 1, 2, 3 or 4 subordinate CA hierarchy. 19 | - Create an optional AWS RAM to share the end-entity subordinate with other accounts at the Org or OU level. 20 | - Save money by removing the need for a private CA in every account by using AWS RAM. 21 | - Create an optional S3 bucket for Certificate Revocation List (CRL). 22 | - Create an optional S3 bucket for CRL access logs. 23 | - Create an optional IAM role for Private CA administration, either in the Private CA account or cross-account with an External ID to protect against [the confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) 24 | - A separate CloudFormation template to create a role for a certificate consumer of Private CA certificates in workload accounts, e.g. to request or renew a certificate 25 | 26 | # Usage 27 | 28 | - Use the AWS CloudFormation template via either the AWS console or AWS Command Line Interface (CLI). 29 | - The template parameter descriptions walk you through the console usage. 30 | - See the Test Cases below for CLI usage. 31 | 32 | # Limitations 33 | 34 | - AWS recommends using Amazon CloudFront to serve CRLs to clients, see [Enable S3 Block Public Access (BPA) with CloudFront](https://docs.aws.amazon.com/privateca/latest/userguide/crl-planning.html#s3-bpa). This AWS CloudFormation template does not have CloudFront creation capabilities at this time. One may add this capability to the template themselves or enable it manually after stack creation. 35 | - This AWS CloudFormation template does not have OCSP enablement capabilities at this time. One may add this capability to the template themselves or enable it manually after stack creation. 36 | - This AWS CloudFormation template does not enable permissions for ACM at this time, see [AWS::ACMPCA::Permission](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-acmpca-permission.html). This is only needed for the ACM principal to renew private PKI certificates requested through ACM and residing in the same AWS account as the CA.One may add this capability to the template themselves or enable it manually after stack creation. 37 | - Private CA Connectors for AD and SCEP require prerequisites that are out of scope for this solution. 38 | 39 | # Prerequisites 40 | 41 | - All CAs will reside in a single account and in a single region. 42 | - Customer generated certificates and keys are NOT required to be imported into the CA. 43 | - The CRL bucket does not require public access. Best practice recommends keeping the CRL private. If internet access to the CRL is required, use Amazon CloudFront to serve the CRLs within the [Enabling the S3 Block Public Access feature](https://docs.aws.amazon.com/privateca/latest/userguide/crl-planning.html#s3-bpa) to ensure there is no public exposure of the S3 bucket origin. 44 | 45 | Use this solution in an AWS Organization environment needing multi-level hierarchy CA or alternatively implement the solution without AWS RAM sharing within a single account. See the AWS whitepaper for [Recommended OUs](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/recommended-ous.html). 46 | 47 | To use this solution with AWS Organizations, the following is recommended: 48 | - Use a Security account for creating the CA Hierarchy and the share. 49 | - Use a separate OU (e.g. Sandbox OU) with one or more accounts for testing certificate management. 50 | - [Enable sharing](https://docs.aws.amazon.com/ram/latest/userguide/getting-started-sharing.html#getting-started-sharing-orgs) within the management account. 51 | 52 | This solution provides two options for sharing to AWS Organizations: 53 | - **Option 1** Create the share at Org level. All accounts in the organization will be able to issue the private certificates using the shared CA. 54 | 55 | ![AWS Organizations sharing option 1](images/AWSOrg-Option1.png) 56 | 57 | - **Option 2** Create the share at the OU level. Only the accounts in the OU will be able to issue the private certificates using the shared CA. For example, if the share is created at the Sandbox OU level then both Developer 1 and Developer 2 will be able to the issue private certificates using the shared CA. 58 | 59 | ![AWS Organizations sharing option 2](images/AWSOrg-Option2.png) 60 | 61 | # Alternatives 62 | 63 | This solution provides a single AWS Region, CA hierarchy with optional cross-account sharing via AWS RAM. AWS Private CA is a regional service so this solution only allows sharing cross-account within the same AWS Region. However, alternate usage patterns could be applied to this solution either by extending it or manually creating additional resources. Some examples of alternate usage patterns are: 64 | 65 | - A CA hierarchy with the root outside of AWS 66 | - Subordinates will need to be signed and activated manually 67 | - A CA hierarchy with some subordinates outside of AWS 68 | - Use this solution to create the single AWS Region CA hierarchy, then manually add subordinates from outside of AWS 69 | - A CA hierarchy all within AWS but involving multiple AWS Regions 70 | - Create the regional CA hierarchy with this solution, then manually add a subordinate hierarchy to the original root CA in other AWS Regions. See https://docs.aws.amazon.com/privateca/latest/userguide/PcaExternalRoot.html for more information. 71 | 72 | # Test Cases 73 | 74 | The solution is tested for the following test cases using the parameter files. 75 | 76 | - `testStackL0.json` 77 | - Root CA, ***no subordinate CAs***, CRL bucket, log bucket with OU level share. This is just for testing. *This is not a recommended approach*. 78 | - `testStackL1.json` 79 | - Root CA, ***1 subordinate CA***, CRL bucket, log bucket with OU level share. 80 | - `testStackL2.json` 81 | - Root CA, ***2 subordinate CAs***, CRL bucket, log bucket with OU level share. 82 | - `testStackL3.json` 83 | - Root CA, ***3 subordinate CAs***, CRL bucket, log bucket with OU level share. 84 | - `testStackL4.json` 85 | - Root CA, ***4 subordinate CAs***, CRL bucket, log bucket with OU level share. 86 | - `testStack-NoCRL.json` 87 | - Root CA, 1 subordinate CA, ***no CRL bucket, no log bucket*** with OU level share. 88 | - `testStack-NoLogBucket.json` 89 | - Root CA, 1 subordinate CA, CRL bucket, ***no log bucket*** with OU level share. 90 | - `testStackL4-orgShare.json` 91 | - Root CA, 4 subordinate CAs, no CRL bucket, no log bucket with ***Org level share***. 92 | - `testStackL4-noShare.json` 93 | - Root CA, 4 subordinate CAs, no CRL bucket, no log bucket and ***no share***. This is just for testing. *This is not a recommended approach*. 94 | 95 | Use the AWS CLI for easy testing. ***Make sure you are using the security account within the shared services OU*** 96 | *Modify the parameter files with your management account, orgID, OU and bucket names* 97 | 98 | ``` 99 | aws cloudformation create-stack --stack-name testStack-L0 --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL0.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 100 | ``` 101 | ``` 102 | aws cloudformation create-stack --stack-name testStack-L1 --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL1.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 103 | ``` 104 | ``` 105 | aws cloudformation create-stack --stack-name testStack-L2 --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL2.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 106 | ``` 107 | ``` 108 | aws cloudformation create-stack --stack-name testStack-L3 --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL3.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 109 | ``` 110 | ``` 111 | aws cloudformation create-stack --stack-name testStack-L4 --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL4.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 112 | ``` 113 | ``` 114 | aws cloudformation create-stack --stack-name testStack-NoCRL --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStack-NoCRL.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 115 | ``` 116 | ``` 117 | aws cloudformation create-stack --stack-name testStack-NoLogBucket --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStack-NoLogBucket.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 118 | ``` 119 | ``` 120 | aws cloudformation create-stack --stack-name testStack-orgShare --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL4-orgShare.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 121 | ``` 122 | ``` 123 | aws cloudformation create-stack --stack-name testStack-noShare --template-body file://AWSPCA-RootCASubCA.yaml --parameters file://testStackL4-noShare.json --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM 124 | ``` 125 | 126 | ## Certificate Lifecycle Tests 127 | 128 | AWS CLI or AWS Console can be used to test the private certificate lifecycle. 129 | You must switch account to test certificate lifecycle. Switch to an account in the Org or OU where the share is created. 130 | 131 | See the sample AWS CLI command below: 132 | 133 | ``` 134 | # Request Certificate. Use the CA ARN from the output of AWS CloudFormation template stack. 135 | aws acm request-certificate --domain-name test1.example.com --options CertificateTransparencyLoggingPreference=DISABLED --certificate-authority-arn arn:aws:acm-pca:::certificate-authority/ 136 | ``` 137 | ``` 138 | # Export Certificate. Use the certificate ARN from the response of request-certificate 139 | aws acm export-certificate --passphrase dGVzdDEyMw== --certificate-arn arn:aws:acm-pca:::certificate/ 140 | ``` 141 | ``` 142 | # Describe Certificate. See if it is eligible for renewal 143 | aws acm describe-certificate --certificate-arn arn:aws:acm-pca:::certificate/ 144 | ``` 145 | ``` 146 | # Renew Certificate, see if renewal is successful using describe-certificate 147 | aws acm renew-certificate --certificate-arn arn:aws:acm-pca:::certificate/ 148 | ``` 149 | ``` 150 | # Delete Certificate 151 | aws acm delete-certificate --certificate-arn arn:aws:acm-pca:::certificate/ 152 | ``` 153 | 154 | ## Test Cleanup 155 | 156 | AWS CLI or AWS Console can be used to clean up resources created for testing. 157 | 158 | See the sample AWS CLI command below for cleanup (*use your bucket names*): 159 | ``` 160 | aws cloudformation delete-stack --stack-name testStack-L0 161 | aws s3 rb s3://mydomain-io-awspca-crl-l0 --force 162 | aws s3 rb s3://mydomain-io-awspca-log-l0 --force 163 | ``` 164 | ``` 165 | aws cloudformation delete-stack --stack-name testStack-L1 166 | aws s3 rb s3://mydomain-io-awspca-crl-l1 --force 167 | aws s3 rb s3://mydomain-io-awspca-log-l1 --force 168 | ``` 169 | ``` 170 | aws cloudformation delete-stack --stack-name testStack-L2 171 | aws s3 rb s3://mydomain-io-awspca-crl-l2 --force 172 | aws s3 rb s3://mydomain-io-awspca-log-l2 --force 173 | ``` 174 | ``` 175 | aws cloudformation delete-stack --stack-name testStack-L3 176 | aws s3 rb s3://mydomain-io-awspca-crl-l3 --force 177 | aws s3 rb s3://mydomain-io-awspca-log-l3 --force 178 | ``` 179 | ``` 180 | aws cloudformation delete-stack --stack-name testStack-L4 181 | aws s3 rb s3://mydomain-io-awspca-crl-l4 --force 182 | aws s3 rb s3://mydomain-io-awspca-log-l4 --force 183 | ``` 184 | ``` 185 | aws cloudformation delete-stack --stack-name testStack-NoLogBucket 186 | aws s3 rb s3://mydomain-io-awspca-crl-l5 --force 187 | ``` 188 | ``` 189 | aws cloudformation delete-stack --stack-name testStack-NoCRL 190 | ``` 191 | ``` 192 | aws cloudformation delete-stack --stack-name testStack-noShare 193 | ``` 194 | ``` 195 | aws cloudformation delete-stack --stack-name testStack-orgShare 196 | ``` 197 | 198 | ## Security 199 | 200 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 201 | 202 | ## License 203 | 204 | This library is licensed under the MIT-0 License. See the LICENSE file. 205 | 206 | -------------------------------------------------------------------------------- /AWSPCA-RootCASubCA.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Transform: AWS::LanguageExtensions 4 | 5 | Description: > 6 | This AWS CloudFormation template deploys an AWS Private CA with a multi-level, 7 | subordinate hierarchy in a specified AWS Region and account. It supports conditionally 8 | specifying the level of subordination. For example, create a root and one subordinate 9 | CA (two CA level hierarchy) by leaving the parameters of subordinates 2-4 blank. 10 | Optionally, create S3 buckets for the Certificate Revocation List (CRL) and for CRL 11 | access logging and optionally share the end-entity certificate generating subordinate 12 | to an AWS organization or organizational unit via AWS Resource Access Manager (AWS RAM). 13 | 14 | # See also https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/simplify-private-certificate-management-by-using-aws-private-ca-and-aws-ram.html 15 | # https://aws.amazon.com/blogs/security/how-to-use-aws-ram-to-share-your-acm-private-ca-cross-account/ 16 | # https://docs.aws.amazon.com/privateca/latest/userguide/ca-hierarchy.html 17 | # https://docs.aws.amazon.com/privateca/latest/userguide/create-CA.html 18 | 19 | Parameters: 20 | # Certificate Subject Info 21 | pOrganization: 22 | Description: The name of the organization for the certificate subject, e.g. MyDomain LLC. Max length of 64 characters. 23 | Type: String 24 | MaxLength: 64 25 | pOrganizationalUnit: 26 | Description: The name of the organizational unit that owns the certificate for the certificate subject, e.g. Cloud IT. Max length of 64 characters. 27 | Type: String 28 | MaxLength: 64 29 | pCountry: 30 | Description: The two character country code for the certificate subject, e.g. US. 31 | Type: String 32 | Default: US 33 | MinLength: 2 34 | MaxLength: 2 35 | AllowedPattern: "[A-Z]*" 36 | pState: 37 | Description: The state for the certificate subject, e.g. California. Max length of 128 characters. 38 | Type: String 39 | MaxLength: 128 40 | pLocality: 41 | Description: The locality for the certificate subject, e.g. Los Angeles. Max length 128 characters. 42 | Type: String 43 | MaxLength: 128 44 | # Certificate Encryption Info 45 | pKeyAlgorithm: 46 | Description: Type of the public key algorithm and size, in bits, of the key pair that your CA creates when it issues a certificate. 47 | Type: String 48 | Default: RSA_2048 49 | AllowedValues: 50 | - RSA_2048 51 | - RSA_4096 52 | - EC_prime256v1 53 | - EC_secp384r1 54 | pSigningAlgorithm: 55 | Description: Name of the algorithm your private CA uses to sign certificate requests. 56 | Type: String 57 | Default: SHA256WITHRSA 58 | AllowedValues: 59 | - SHA256WITHECDSA 60 | - SHA256WITHRSA 61 | - SHA384WITHECDSA 62 | - SHA384WITHRSA 63 | - SHA512WITHECDSA 64 | - SHA512WITHRSA 65 | # Root Certificate Authority Info 66 | pRootCommonName: 67 | Description: Fully qualified domain name (FQDN) associated with the certificate subject, e.g. mydomain.io. Max length of 64 characters. 68 | Type: String 69 | MaxLength: 64 70 | pRootCACertExpiry: 71 | Description: Certificate expiration in days, e.g. 3651. 72 | Type: String 73 | Default: 3651 74 | pRootCRLExpiry: 75 | Description: Root CRL expiry in days, must be higher than the subordinate CRL expiry, e.g. 90. 76 | Type: String 77 | Default: 90 78 | # 1st Level Subordinate Certificate Authority Info 79 | pSub1CommonName: 80 | Description: Fully qualified domain name (FQDN) associated with the certificate subject, e.g. subdomain1.mydomain.io. Leave this blank to skip building this subordinate CA, not best practice to have no subordinates. Max length of 64 characters. 81 | Type: String 82 | MaxLength: 64 83 | pSub1CACertExpiry: 84 | Description: Certificate expiration in days, e.g. 1825. Must be smaller than higher level CAs. 85 | Type: String 86 | Default: 1825 87 | pSub1CRLExpiry: 88 | Description: 1st Subordinate CRL expiry in days, must be smaller than higher level CAs, e.g. 60. 89 | Type: String 90 | Default: 60 91 | # 2nd Level Subordinate Certificate Authority Info 92 | pSub2CommonName: 93 | Description: Fully qualified domain name (FQDN) associated with the certificate subject, e.g. subdomain2.subdomain1.mydomain.io. Leave this blank to skip building this subordinate CA. Max length of 64 characters. 94 | Type: String 95 | MaxLength: 64 96 | pSub2CACertExpiry: 97 | Description: Certificate expiration in days, e.g. 1095. Must be smaller than higher level CAs. 98 | Type: String 99 | Default: 1095 100 | pSub2CRLExpiry: 101 | Description: 2nd Subordinate CRL expiry in days, must be smaller than higher level CAs, e.g. 50. 102 | Type: String 103 | Default: 50 104 | # 3rd Level Subordinate Certificate Authority Info 105 | pSub3CommonName: 106 | Description: Fully qualified domain name (FQDN) associated with the certificate subject, e.g. subdomain3.subdomain2.subdomain1.mydomain.io. Leave this blank to skip building this subordinate CA. Max length of 64 characters. 107 | Type: String 108 | MaxLength: 64 109 | pSub3CACertExpiry: 110 | Description: Certificate expiration in days, e.g. 730. Must be smaller than higher level CAs. 111 | Type: String 112 | Default: 730 113 | pSub3CRLExpiry: 114 | Description: 1st Subordinate CRL expiry in days, must be smaller than higher level CAs, e.g. 40. 115 | Type: String 116 | Default: 40 117 | # 4th Level Subordinate Certificate Authority Info 118 | pSub4CommonName: 119 | Description: Fully qualified domain name (FQDN) associated with the certificate subject, e.g. subdomain4.subdomain3.subdomain2.subdomain1.mydomain.io. Leave this blank to skip building this subordinate CA. Max length of 64 characters. 120 | Type: String 121 | MaxLength: 64 122 | pSub4CACertExpiry: 123 | Description: Certificate expiration in days, e.g. 365. Must be smaller than higher level CAs. 124 | Type: String 125 | Default: 365 126 | pSub4CRLExpiry: 127 | Description: 1st Subordinate CRL expiry in days, must be smaller than higher level CAs, e.g. 30. 128 | Type: String 129 | Default: 30 130 | # Optional buckets 131 | pRootCRLBucket: 132 | Description: Name of S3 bucket for the CRL, e.g. mydomain-io-awspca-crl. Leaving this blank will disable CRL. 133 | Type: String 134 | pLogCRLBucket: 135 | Description: Name of S3 bucket where the log of CRL access is stored, e.g. mydomain-io-awspca-log. Leaving this blank will disable CRL access logging. 136 | Type: String 137 | # AWS Organization Account Info 138 | pManagmentAccount: 139 | Description: Share the lowest level CA to the specified AWS Organizations management account, e.g., 112233445566. Leaving this blank will not create the AWS RAM share. 140 | Type: String 141 | pAWSOrganizationId: 142 | Description: Share the lowest level CA to the specified AWS Organization e.g., o-fortestorg. Required with account ID above for the AWS RAM share. Include an OU below to share at the OU level. 143 | Type: String 144 | Default: "" 145 | pAWSOrganizationalUnit: 146 | Description: Share the lowest level CA to the specified AWS Organizational Unit e.g. ou-foratestou. Leave this blank and include an Org ID above to share at the Organization level. 147 | Type: String 148 | Default: "" 149 | # Optional roles 150 | pPCAAdminRoleName: 151 | Description: Name of the Private CA Administration role, e.g. PCAAdmin. Leave blank to skip this role 152 | Default: "" 153 | Type: String 154 | pPCAAdminPermissionsBoundary: 155 | Description: Permissions Boundary ARN for PCA Admin, this policy must be pre-defined. Leave blank to skip the permissions boundary. AWS best practices recommends using a permissions boundary. 156 | Type: String 157 | Default: "" 158 | pPCAAdminAccounts: 159 | Description: Comma separated list of AWS Account number for the principal that assumes the Private CA Administration role, leave blank to use the local PCA account only in the trust policy. 160 | Type: CommaDelimitedList 161 | Default: "" 162 | pPCAExternalId: 163 | Description: External ID to be used when assuming the roles, e.g. ExternalPCARole. Leave blank to use the local PCA account only. AWS best practices suggests using an external ID with cross-account roles. 164 | Type: String 165 | Default: "" 166 | 167 | Metadata: 168 | AWS::CloudFormation::Interface: 169 | ParameterGroups: 170 | - Label: 171 | default: "Certificate Subject Info" 172 | Parameters: 173 | - pOrganization 174 | - pOrganizationalUnit 175 | - pCountry 176 | - pState 177 | - pLocality 178 | - Label: 179 | default: "Certificate Encryption Info" 180 | Parameters: 181 | - pKeyAlgorithm 182 | - pSigningAlgorithm 183 | - Label: 184 | default: "Root Certificate Authority Info" 185 | Parameters: 186 | - pRootCommonName 187 | - pRootCACertExpiry 188 | - pRootCRLBucket 189 | - pRootCRLExpiry 190 | - pLogCRLBucket 191 | - Label: 192 | default: "1st Level Subordinate Certificate Authority Info" 193 | Parameters: 194 | - pSub1CommonName 195 | - pSub1CACertExpiry 196 | - pSub1CRLExpiry 197 | - Label: 198 | default: "2nd Level Subordinate Certificate Authority Info" 199 | Parameters: 200 | - pSub2CommonName 201 | - pSub2CACertExpiry 202 | - pSub2CRLExpiry 203 | - Label: 204 | default: "3rd Level Subordinate Certificate Authority Info" 205 | Parameters: 206 | - pSub3CommonName 207 | - pSub3CACertExpiry 208 | - pSub3CRLExpiry 209 | - Label: 210 | default: "4th Level Subordinate Certificate Authority Info" 211 | Parameters: 212 | - pSub4CommonName 213 | - pSub4CACertExpiry 214 | - pSub4CRLExpiry 215 | - Label: 216 | default: "AWS Organization Account Info" 217 | Parameters: 218 | - pManagmentAccount 219 | - pAWSOrganizationId 220 | - pAWSOrganizationalUnit 221 | - Label: 222 | default: "IAM Roles" 223 | Parameters: 224 | - pPCAAdminRoleName 225 | - pPCAAdminPermissionsBoundary 226 | - pPCAAdminAccounts 227 | - pPCAExternalId 228 | # Define user friendly names for the parameters 229 | ParameterLabels: 230 | pOrganization: 231 | default: Organization 232 | pOrganizationalUnit: 233 | default: Organizational Unit 234 | pCountry: 235 | default: Country 236 | pState: 237 | default: State 238 | pLocality: 239 | default: Locality 240 | pKeyAlgorithm: 241 | default: Key Algorithm 242 | pSigningAlgorithm: 243 | default: SigningAlgorithm 244 | pRootCommonName: 245 | default: Common Name 246 | pRootCACertExpiry: 247 | default: Certificate Expiry 248 | pRootCRLExpiry: 249 | default: CRL Expiry 250 | pSub1CommonName: 251 | default: Common Name 252 | pSub1CACertExpiry: 253 | default: Certificate Expiry 254 | pSub1CRLExpiry: 255 | default: CRL Expiry 256 | pSub2CommonName: 257 | default: Common Name 258 | pSub2CACertExpiry: 259 | default: Certificate Expiry 260 | pSub2CRLExpiry: 261 | default: CRL Expiry 262 | pSub3CommonName: 263 | default: Common Name 264 | pSub3CACertExpiry: 265 | default: Certificate Expiry 266 | pSub3CRLExpiry: 267 | default: CRL Expiry 268 | pSub4CommonName: 269 | default: Common Name 270 | pSub4CACertExpiry: 271 | default: Certificate Expiry 272 | pSub4CRLExpiry: 273 | default: CRL Expiry 274 | pRootCRLBucket: 275 | default: CRL Bucket Name 276 | pLogCRLBucket: 277 | default: Log Bucket Name 278 | pManagmentAccount: 279 | default: AWS Organizations Management Account 280 | pAWSOrganizationId: 281 | default: AWS Organization Id 282 | pAWSOrganizationalUnit: 283 | default: AWS Organizational Unit 284 | pPCAAdminRoleName: 285 | default: Private CA Admin Role Name 286 | pPCAAdminPermissionsBoundary: 287 | default: Private CA Admin Permissions Boundary 288 | pPCAAdminAccounts: 289 | default: Private CA Admin Account 290 | pPCAExternalId: 291 | default: Private CA External ID 292 | 293 | Conditions: 294 | # Do not create subordinates if their certificate subject common names are left blank 295 | # If Sub1 is not built, don't build any others. These subordinates must be built in order 296 | EnableCRL: !Not 297 | - !Equals 298 | - !Ref pRootCRLBucket 299 | - "" 300 | EnableCRLLog: !And 301 | - !Condition EnableCRL 302 | - !Not 303 | - !Equals 304 | - !Ref pLogCRLBucket 305 | - "" 306 | CreateSub1: !Not 307 | - !Equals 308 | - !Ref pSub1CommonName 309 | - "" 310 | CreateSub2: !And 311 | - !Condition CreateSub1 312 | - !Not 313 | - !Equals 314 | - !Ref pSub2CommonName 315 | - "" 316 | CreateSub3: !And 317 | - !Condition CreateSub2 318 | - !Not 319 | - !Equals 320 | - !Ref pSub3CommonName 321 | - "" 322 | CreateSub4: !And 323 | - !Condition CreateSub3 324 | - !Not 325 | - !Equals 326 | - !Ref pSub4CommonName 327 | - "" 328 | CreateOrgShare: !And 329 | - !Not 330 | - !Equals 331 | - !Ref pManagmentAccount 332 | - "" 333 | - !Not 334 | - !Equals 335 | - !Ref pAWSOrganizationId 336 | - "" 337 | CreateOUShare: !And 338 | - !Condition CreateOrgShare 339 | - !Not 340 | - !Equals 341 | - !Ref pAWSOrganizationalUnit 342 | - "" 343 | CreateShare: !Or 344 | - !Condition CreateOrgShare 345 | - !Condition CreateOUShare 346 | CreateRootShare: !And 347 | - !Condition CreateShare 348 | - !Not 349 | - !Condition CreateSub1 350 | CreateSub1Share: !And 351 | - !Condition CreateShare 352 | - !And 353 | - !Condition CreateSub1 354 | - !Not 355 | - !Condition CreateSub2 356 | CreateSub2Share: !And 357 | - !Condition CreateShare 358 | - !And 359 | - !Condition CreateSub2 360 | - !Not 361 | - !Condition CreateSub3 362 | CreateSub3Share: !And 363 | - !Condition CreateShare 364 | - !And 365 | - !Condition CreateSub3 366 | - !Not 367 | - !Condition CreateSub4 368 | CreateSub4Share: !And 369 | - !Condition CreateShare 370 | - !Condition CreateSub4 371 | CreatePCAAdminRole: !Not 372 | - !Equals 373 | - !Ref pPCAAdminRoleName 374 | - "" 375 | CreatePCAAdminRoleWithBoundary: !Not 376 | - !Equals 377 | - !Ref pPCAAdminPermissionsBoundary 378 | - "" 379 | UseLocalPCAAccountForAdmin: !Equals 380 | - !Join ["", !Ref pPCAAdminAccounts] 381 | - "" 382 | # No need for an external ID if not using a cross-account role 383 | UseExternalId: !And 384 | - !Not 385 | - !Condition UseLocalPCAAccountForConsumer 386 | - !Not 387 | - !Equals 388 | - !Ref pPCAExternalId 389 | - "" 390 | 391 | Resources: 392 | rLogCRLBucket: 393 | # checkov:skip=CKV_AWS_18: The solution does not require access logging for this bucket. 394 | # checkov:skip=CKV_AWS_21: The solution does not require versioning on S3 395 | Type: AWS::S3::Bucket 396 | Metadata: 397 | cfn_nag: 398 | rules_to_suppress: 399 | - id: W51 400 | reason: "This is logging bucket, AccessControl = LogDeliveryWrite" 401 | - id: W35 402 | reason: "The solution does not require access logging for this bucket" 403 | cfn-lint: 404 | config: 405 | ignore_checks: 406 | - W3011 407 | Condition: EnableCRLLog 408 | DeletionPolicy: Retain 409 | Properties: 410 | BucketName: !Ref pLogCRLBucket 411 | AccessControl: LogDeliveryWrite 412 | BucketEncryption: # SSE-S3 vs SSE-KMS, AWS vs Customer KMS 413 | ServerSideEncryptionConfiguration: 414 | - ServerSideEncryptionByDefault: 415 | SSEAlgorithm: AES256 416 | # LifecycleConfiguration: 417 | Tags: 418 | - Key: "Purpose" 419 | Value: "AWSPCA CRL Access Logs" 420 | PublicAccessBlockConfiguration: 421 | RestrictPublicBuckets: True 422 | BlockPublicAcls: True 423 | BlockPublicPolicy: True 424 | IgnorePublicAcls: True 425 | rRootCRLBucket: 426 | # checkov:skip=CKV_AWS_21: The solution does not require versioning on S3 427 | Type: AWS::S3::Bucket 428 | Metadata: 429 | cfn-lint: 430 | config: 431 | ignore_checks: 432 | - W3011 433 | Condition: EnableCRL 434 | DeletionPolicy: Retain 435 | Properties: 436 | BucketName: !Ref pRootCRLBucket 437 | AccessControl: Private 438 | OwnershipControls: 439 | Rules: 440 | - ObjectOwnership: BucketOwnerPreferred 441 | LoggingConfiguration: !If 442 | - EnableCRLLog 443 | - DestinationBucketName: !Ref rLogCRLBucket 444 | LogFilePrefix: RootCA 445 | - !Ref "AWS::NoValue" 446 | BucketEncryption: # SSE-S3 vs SSE-KMS, AWS vs Customer KMS 447 | ServerSideEncryptionConfiguration: 448 | - ServerSideEncryptionByDefault: 449 | SSEAlgorithm: AES256 450 | Tags: 451 | - Key: "Purpose" 452 | Value: "AWSPCA Certificate Revocation List" 453 | PublicAccessBlockConfiguration: 454 | RestrictPublicBuckets: True 455 | BlockPublicAcls: True 456 | BlockPublicPolicy: True 457 | IgnorePublicAcls: True 458 | rRootCRLBucketPolicy: 459 | Type: AWS::S3::BucketPolicy 460 | Condition: EnableCRL 461 | Properties: 462 | Bucket: !Ref rRootCRLBucket 463 | PolicyDocument: 464 | Statement: 465 | - Sid: AllowAWSPCAPutObjectAccessForCRLAndChainCertificates 466 | Action: 467 | - "s3:GetBucketAcl" 468 | - "s3:GetBucketLocation" 469 | - "s3:PutObject" 470 | - "s3:PutObjectAcl" 471 | Effect: "Allow" 472 | Resource: 473 | - !Join ["", ["arn:aws:s3:::", !Ref pRootCRLBucket, "/*"]] 474 | - !Join ["", ["arn:aws:s3:::", !Ref pRootCRLBucket]] 475 | Principal: 476 | Service: 477 | - "acm-pca.amazonaws.com" 478 | # Bucket Policy has to be created before using it in RootCA 479 | BucketPolicyWaitHandle: 480 | Condition: EnableCRL 481 | DependsOn: rRootCRLBucketPolicy 482 | Type: "AWS::CloudFormation::WaitConditionHandle" 483 | BlankWaitHandle: 484 | Type: "AWS::CloudFormation::WaitConditionHandle" 485 | BucketPolicyWaitCondition: 486 | Type: "AWS::CloudFormation::WaitCondition" 487 | Properties: 488 | Handle: !If [EnableCRL, !Ref BucketPolicyWaitHandle, !Ref BlankWaitHandle] 489 | Timeout: "5" 490 | Count: 0 491 | rRootCA: 492 | Type: AWS::ACMPCA::CertificateAuthority 493 | DependsOn: BucketPolicyWaitCondition 494 | Properties: 495 | Type: ROOT 496 | Subject: 497 | CommonName: !Ref pRootCommonName 498 | Organization: !Ref pOrganization 499 | OrganizationalUnit: !Ref pOrganizationalUnit 500 | Country: !Ref pCountry 501 | State: !Ref pState 502 | Locality: !Ref pLocality 503 | KeyAlgorithm: !Ref pKeyAlgorithm 504 | SigningAlgorithm: !Ref pSigningAlgorithm 505 | RevocationConfiguration: 506 | CrlConfiguration: !If 507 | - EnableCRL 508 | - Enabled: true 509 | ExpirationInDays: !Ref pRootCRLExpiry 510 | S3BucketName: !Ref rRootCRLBucket 511 | S3ObjectAcl: "BUCKET_OWNER_FULL_CONTROL" 512 | - Enabled: false 513 | Tags: 514 | - Key: "Purpose" 515 | Value: "Root CA" 516 | rRootCACert: 517 | Type: "AWS::ACMPCA::Certificate" 518 | Properties: 519 | CertificateAuthorityArn: !Ref rRootCA 520 | CertificateSigningRequest: !GetAtt rRootCA.CertificateSigningRequest 521 | SigningAlgorithm: !Ref pSigningAlgorithm 522 | TemplateArn: "arn:aws:acm-pca:::template/RootCACertificate/V1" 523 | Validity: 524 | Type: DAYS 525 | Value: !Ref pRootCACertExpiry 526 | rRootCAActivation: 527 | Type: "AWS::ACMPCA::CertificateAuthorityActivation" 528 | Properties: 529 | CertificateAuthorityArn: !Ref rRootCA 530 | Certificate: !GetAtt rRootCACert.Certificate 531 | Status: ACTIVE 532 | # Iterate through creation of requested subordinates 533 | 'Fn::ForEach::SubordinateCA': 534 | - Level 535 | - ["1", "2", "3", "4"] 536 | - 'rSubordinateCA${Level}': 537 | Type: AWS::ACMPCA::CertificateAuthority 538 | Condition: !Sub 'CreateSub${Level}' 539 | DependsOn: rRootCA 540 | Properties: 541 | Type: SUBORDINATE 542 | Subject: 543 | CommonName: !Ref 544 | 'Fn::Sub': 'pSub${Level}CommonName' 545 | Organization: !Ref pOrganization 546 | OrganizationalUnit: !Ref pOrganizationalUnit 547 | Country: !Ref pCountry 548 | State: !Ref pState 549 | Locality: !Ref pLocality 550 | KeyAlgorithm: !Ref pKeyAlgorithm 551 | SigningAlgorithm: !Ref pSigningAlgorithm 552 | RevocationConfiguration: 553 | CrlConfiguration: !If 554 | - EnableCRL 555 | - Enabled: true 556 | ExpirationInDays: !Ref 557 | 'Fn::Sub': 'pSub${Level}CRLExpiry' 558 | S3BucketName: !Ref rRootCRLBucket 559 | S3ObjectAcl: "BUCKET_OWNER_FULL_CONTROL" 560 | - Enabled: false 561 | Tags: 562 | - Key: "Purpose" 563 | Value: !Sub 'Subordinate CA${Level}' 564 | 'rSubordinateCA${Level}Cert': 565 | Type: "AWS::ACMPCA::Certificate" 566 | Condition: !Sub 'CreateSub${Level}' 567 | DependsOn: rRootCAActivation 568 | Properties: 569 | CertificateAuthorityArn: !Ref rRootCA 570 | CertificateSigningRequest: !GetAtt 571 | - 'Fn::Sub': 'rSubordinateCA${Level}' 572 | - CertificateSigningRequest 573 | SigningAlgorithm: !Ref pSigningAlgorithm 574 | TemplateArn: !If 575 | - CreateSub4 576 | - "arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen3/V1" 577 | - !If 578 | - CreateSub3 579 | - "arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen2/V1" 580 | - !If 581 | - CreateSub2 582 | - "arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen1/V1" 583 | - !If 584 | - CreateSub1 585 | - "arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0/V1" 586 | - !Ref "AWS::NoValue" 587 | Validity: 588 | Type: DAYS 589 | Value: !Ref 590 | 'Fn::Sub': 'pSub${Level}CACertExpiry' 591 | 'rSubordinateCA${Level}Activation': 592 | Type: "AWS::ACMPCA::CertificateAuthorityActivation" 593 | Condition: !Sub 'CreateSub${Level}' 594 | Properties: 595 | CertificateAuthorityArn: !Ref 596 | 'Fn::Sub': 'rSubordinateCA${Level}' 597 | Certificate: !GetAtt 598 | - 'Fn::Sub': 'rSubordinateCA${Level}Cert' 599 | - Certificate 600 | CertificateChain: !GetAtt rRootCAActivation.CompleteCertificateChain 601 | Status: ACTIVE 602 | # Only turn this on if there are no subordinates, otherwise share only lowest level subordinate 603 | rRootShare: 604 | Type: AWS::RAM::ResourceShare 605 | Condition: CreateRootShare 606 | DependsOn: rRootCAActivation 607 | Properties: 608 | AllowExternalPrincipals: false 609 | Name: !Sub 610 | - "RootCAResourceShare-${CommonName}" 611 | - CommonName: !Ref pRootCommonName 612 | Principals: !If 613 | - CreateOUShare 614 | - - !Sub "arn:aws:organizations::${pManagmentAccount}:ou/${pAWSOrganizationId}/${pAWSOrganizationalUnit}" 615 | - !If 616 | - CreateOrgShare 617 | - - !Sub "arn:aws:organizations::${pManagmentAccount}:organization/${pAWSOrganizationId}" 618 | - !Ref "AWS::NoValue" 619 | ResourceArns: 620 | - !Ref rRootCA 621 | Tags: 622 | - Key: "Purpose" 623 | Value: "Private CA for certificate signing" 624 | # Iterate through creation of requested subordinate shares 625 | 'Fn::ForEach::SubordinateCAShare': 626 | - Level 627 | - ["1", "2", "3", "4"] 628 | - 'rSubordinateCA${Level}Share': 629 | Type: AWS::RAM::ResourceShare 630 | Condition: !Sub 'CreateSub${Level}Share' 631 | DependsOn: !Sub 'rSubordinateCA${Level}Activation' 632 | Properties: 633 | AllowExternalPrincipals: false 634 | Name: !Sub 635 | - "SubordinateCAResourceShare-${CommonName}" 636 | - CommonName: !Ref 637 | 'Fn::Sub': 'pSub${Level}CommonName' 638 | Principals: !If 639 | - CreateOUShare 640 | - - !Sub "arn:aws:organizations::${pManagmentAccount}:ou/${pAWSOrganizationId}/${pAWSOrganizationalUnit}" 641 | - !If 642 | - CreateOrgShare 643 | - - !Sub "arn:aws:organizations::${pManagmentAccount}:organization/${pAWSOrganizationId}" 644 | - !Ref "AWS::NoValue" 645 | ResourceArns: 646 | - !Ref 647 | 'Fn::Sub': 'rSubordinateCA${Level}' 648 | Tags: 649 | - Key: "Purpose" 650 | Value: "Private CA for certificate signing" 651 | rPCAAdminRole: 652 | UpdateReplacePolicy: "Delete" 653 | Type: "AWS::IAM::Role" 654 | Condition: CreatePCAAdminRole 655 | DeletionPolicy: "Delete" 656 | Properties: 657 | RoleName: !Ref pPCAAdminRoleName 658 | Description: "Private CA administration role" 659 | AssumeRolePolicyDocument: 660 | Statement: 661 | - Effect: Allow 662 | Action: sts:AssumeRole 663 | Principal: 664 | AWS: !If 665 | - UseLocalPCAAccountForAdmin 666 | - !Ref AWS::AccountId 667 | - !Ref pPCAAdminAccounts 668 | Condition: !If 669 | - UseLocalPCAAccountForAdmin 670 | - !Ref "AWS::NoValue" 671 | - !If 672 | - UseExternalId 673 | - StringEquals: 674 | "sts:ExternalId": !Ref pPCAExternalId 675 | - !Ref "AWS::NoValue" 676 | ManagedPolicyArns: 677 | - arn:aws:iam::aws:policy/AWSPrivateCAFullAccess 678 | PermissionsBoundary: !If 679 | - CreatePCAAdminRoleWithBoundary 680 | - !Ref pPCAAdminPermissionsBoundary 681 | - !Ref "AWS::NoValue" 682 | Path: "/" 683 | Tags: 684 | - Key: "Purpose" 685 | Value: "Admin role for Private CA" 686 | 687 | # Output of stacks are buckets and certificate authority ARNs 688 | Outputs: 689 | oCRLBucket: 690 | Condition: EnableCRL 691 | Description: The CRL bucket 692 | Value: !Ref rRootCRLBucket 693 | Export: 694 | Name: !Sub "${AWS::StackName}-CRLBucket" 695 | oAccessLogBucket: 696 | Condition: EnableCRLLog 697 | Description: The Access Log bucket 698 | Value: !Ref rLogCRLBucket 699 | Export: 700 | Name: !Sub "${AWS::StackName}-AccessLogBucket" 701 | oRootCA: 702 | Description: The ARN of the Root Certificate Authority that can be used by other stacks 703 | Value: !Ref rRootCA 704 | Export: 705 | Name: !Sub "${AWS::StackName}-RootCA" 706 | 'Fn::ForEach::oSubordinateCA': 707 | - Level 708 | - ["1", "2", "3", "4"] 709 | - 'oSubordinateCA${Level}': 710 | Description: !Sub 'The ARN of the subordinate Certificate Authorities for SubordinateCA${Level}' 711 | Condition: !Sub 'CreateSub${Level}' 712 | Value: !Ref 713 | 'Fn::Sub': 'rSubordinateCA${Level}' 714 | Export: 715 | Name: !Sub '${AWS::StackName}-SubordinateCA${Level}' 716 | 'Fn::ForEach::oSubordinateCAShare': 717 | - Level 718 | - ["1", "2", "3", "4"] 719 | - 'oSubordinateCA${Level}Share': 720 | Description: !Sub 'The ARN of the Certificate Authority AWS RAM shares for SubordinateCA${Level}' 721 | Condition: !Sub 'CreateSub${Level}Share' 722 | Value: !Ref 723 | 'Fn::Sub': 'rSubordinateCA${Level}Share' 724 | Export: 725 | Name: !Sub '${AWS::StackName}-CAShare${Level}' 726 | oPCAAdminRole: 727 | Condition: CreatePCAAdminRole 728 | Value: !GetAtt rPCAAdminRole.Arn --------------------------------------------------------------------------------