AWS Private CA now supports custom extensions, such as name constraints. Name constraints allow you to permit or deny specific DNS subject names for certificates issued by the Private CA. For example, your development Private CA can be configured to only allow certificates to be issued for *.dev.example.com whereas a separate Private CA for testers will only allow certificates to be issued for *.test.example.com.
- Python 3.7.15 or later version installed on your local machine.
- pip 20.2.2 or later version installed on your local machine.
- ACM Private CA root CA deployed
- ACM Private CA subordinate CA deployed
- IAM permissions to issue, download, and install CA certificates.
- AWS Command Line Interface (AWS CLI) 2.9.13 or later installed.
- jq command line tool.
- Encode your custom name constraints and generate an API passthrough file using the Python script.
- Generate a Certificate Signing Request (CSR) from the Subordinate CA.
- Use the Root CA to issue a new certificate with the name constraints custom extension.
- Install the name constraints certificate on the Subordinate CA.
- Check the status of the Subordinate CA
- Test Subordinate CA name constraints.
-
Clone the repository
git clone [email protected]:raduraul/aws-private-ca-name-constraints.git
-
Optional: Create a Python virtual environment to run the code for this solution
Creating a Python virtual environment will allow you to run this solution in a fresh environment without impacting your existing Python packages. The virtual environment has its own independent set of Python packages installed. Read the official Python documentation on virtual environments for more information on their purpose and functionality.
- Create a new directory for the Python virtual environment in the users home path.
mkdir ~/python-venv-for-aws-private-ca-name-constraints
- Create a Python virtual environment using the directory created above.
python -m venv ~/python-venv-for-aws-private-ca-name-constraints
- Activate the Python virtual environment.
source ~/python-venv-for-aws-private-ca-name-constraints/bin/activate
- Upgrade pip to the latest version.
python -m pip install --upgrade pip
- Create a new directory for the Python virtual environment in the users home path.
-
Navigate to the solution source directory
cd <your-path>/aws-private-ca-name-constraints/src/
-
Install the necessary python packages and dependencies
Run the command below from the solutions src directory to install the required packages.
pip install -r <your-path>/aws-private-ca-name-constraints/src/requirements.txt
-
Generate the API Passthrough File Using the Python Script
Run the Python code to generate the encoded value for the name constraints you would like to apply to your subordinate CA. Read the documentation for name constraints in RFC5280 for more information on their functionality.
The -p option will allow you to define the permitted subtrees. Separate them using commas if there are multiple.
The -e option will allow you to define the excluded subtrees. Separate them using commas if there are multiple.
For example:
python name-constraints-encoder.py -p .dev.example.com,.test.example.com -e .prod.dev.example.com
If the script ran successfully you will see output similar to the screenshot below.
-
Verify the API Passthrough File
The api_passthrough_config.json file generated by the Python script should look similar to the example below.
Note, the nameConstraints OID is 2.5.29.30. Reference the Global OID database.
The value is generated by the name-constraints-encoder.py Python code and is a base64 representation of the encoded ASN.1 name constraints object.
api_passthrough_config.json content example:
{ "Extensions": { "CustomExtensions": [ { "ObjectIdentifier": "2.5.29.30", "Value": "MFugPjASghAuZGV2LmV4YW1wbGUuY29tMBOCES5wcm9kLmV4YW1wbGUuY29tMBOCES50ZXN0LmV4YW1wbGUuY29toRkwF4IVLnByb2QuZGV2LmV4YW1wbGUuY29t", "Critical": true } ] } }
-
Update your AWS CLI to the current version
Older versions of the AWS CLI will NOT work with the AWS CLI commands listed below and will result in a Parameter validation error as shown below.
Please update your AWS CLI to the latest version.
Example error output when using an older version of the AWS CLI:
Parameter validation failed: Unknown parameter in ApiPassthrough.Extensions: "CustomExtensions", must be one of: CertificatePolicies, ExtendedKeyUsage, KeyUsage, SubjectAlternativeNames
Note: The testing below was done using the following version of the AWS CLI: aws-cli/2.9.13
-
Navigate to the directory containing the API Passthrough File
cd <your-path>/aws-private-ca-name-constraints/src/
-
Generate a CSR From your Private CA
-
Obtain the arn from your subordinate CA and paste it into the command below.
-
Update the region to the region where your subordinate CA is deployed.
aws acm-pca get-certificate-authority-csr \ --certificate-authority-arn arn:aws:acm-pca:us-west-2:111111111111:certificate-authority/cdd22222-2222-2f22-bb2e-222f222222ab \ --output text \ --region us-west-2 > ca.csr
-
-
Optional: View your Subordinate CA CSR
openssl req -text -noout -verify -in ca.csr
The screenshot below shows example output. Note that your Subordinate CA's CSR details will be different.
-
Issue a new certificate from your Root CA
- Obtain the arn from your root CA and paste it into the command below.
- Provide the path to the CSR generated above in the command below.
- Update the signing-algorithm to your desired algorithm. See the AWS Documentation for supported algorithms.
- Provide the path to the api_passthrough_config.json generated by the Python script.
- Update the validity period to your desired validity period. Default below is 1825 days or 5 years.
aws acm-pca issue-certificate \ --certificate-authority-arn arn:aws:acm-pca:us-west-2:111111111111:certificate-authority/111f1111-ba1b-1111-b11d-11ce1a11afae \ --csr fileb://ca.csr \ --signing-algorithm SHA256WITHRSA \ --template-arn arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0_APIPassthrough/V1 \ --api-passthrough file://api_passthrough_config.json \ --validity Value=1825,Type=DAYS
-
If the command is successful, the output will provide the arn of the certificate issued by the Root CA.
-
Write down the certificate arn provided by the issue-certificate command above.
For example:
arn:aws:acm-pca:us-west-2:11111111111:certificate-authority/111f1111-ba1b-1111-b11d-11ce1a11afae/certificate/c555ced55c5a55aaa5f555e5555fd5f5
-
Download the New Certificate With Name Constraints
- Update the certificate-authority-arn with the arn from your root CA and paste it into the command below.
- Update certificate-arn with the arn of the certificate that was issued in the previous step.
aws acm-pca get-certificate \ --certificate-authority-arn arn:aws:acm-pca:us-west-2:111111111111:certificate-authority/111f1111-ba1b-1111-b11d-11ce1a11afae \ --certificate-arn arn:aws:acm-pca:us-west-2:11111111111:certificate-authority/111f1111-ba1b-1111-b11d-11ce1a11afae/certificate/c555ced55c5a55aaa5f555e5555fd5f5 \ --output json > cert.json
-
Separate the Certificate and Certificate Chain into two separate files
- cert.pem for the subordinate CA certificate
- cert_chain.pem for the root CA certificate chain details
Run the following commands:
cat cert.json | jq -r .Certificate > cert.pem cat cert.json | jq -r .CertificateChain > cert_chain.pem
-
Verify the new certificate and chain
openssl x509 -in cert.pem -text -noout openssl x509 -in cert_chain.pem -text -noout
Ensure that the name constraints portion of the certificate is correct.
There are two options for installing the certificate on your Subordinate CA.
Import and install the new certificate with name constraints on your Subordinate CA.
Update the certificate-authority-arn with the arn of your Subordinate CA and run the command below.
aws acm-pca import-certificate-authority-certificate \
--certificate-authority-arn arn:aws:acm-pca:us-west-2:111111111111:certificate-authority/111f1111-ba1b-1111-b11d-11ce1a11afae \
--certificate fileb://cert.pem \
--certificate-chain fileb://cert_chain.pem
-
If you are not already on the CA's details page, open the AWS Private CA console at https://console.aws.amazon.com/acm-pca/home
-
Select your Subordinate CA from the Private certificate authorities page. The subordinate CA may have a status of Pending certificate or Active.
-
Choose Install CA Certificate from the Actions menu.
-
From the Install subordinate CA certificate page select External Private CA.
-
Scroll down to the Import a signed certificate authority (CA) certificate section.
- Upload cert.pem using the Upload button or paste the contents of cert.pem into the certificate body input box.
- Upload cert_chain.pem using the Upload button or paste the contents of cert_chain.pem into the certificate chain input box.
- Select Confirm and Install.
Update and run the command below with the certificate-authority-arn for your Subordinate CA.
aws acm-pca describe-certificate-authority \
--certificate-authority-arn arn:aws:acm-pca:us-west-2:111111111111:certificate-authority/cdd22222-2222-2f22-bb2e-222f222222ab \
--output json
Your output should be similar to the screenshot below. Note that the Subordinate CA will now reflect the new validity period from the name constraints certificate in the NotBefore and NotAfter fields.
-
Request a new certificate from your Subordinate CA
Update the command below with your certificate authority arn and the domain name for the requested certificate.
aws acm request-certificate --certificate-authority-arn arn:aws:acm-pca:us-west-2:111111111111:certificate-authority/cdd22222-2222-2f22-bb2e-222f222222ab --domain-name app.prod.dev.example.com
Take note of the certificate arn output by this command, you will need it in the subsequent step.
-
Describe the new certificate to check its status
Update and run the command below using the certificate arn from the previous step.
aws acm describe-certificate --certificate-arn arn:aws:acm:us-west-2:11111111111:certificate/f11aa1dc-1111-1d1f-1afd-4cb11111b111
-
Interpreting the describe certificate output
If the new certificate request fails you will see output similar to the screenshots below.
In this case a certificate with a domain name of app.prod.dev.example.com was not permitted because the excluded subtrees doesn't allow certificates for *.prod.dev.example.com to be created.
Global OID Database: https://oidref.com/
Name Constraints OID: https://www.alvestrand.no/objectid/2.5.29.30.html
RFC 5280: https://www.rfc-editor.org/rfc/rfc5280
ASN.1 Encoder/Decoder: https://asn1.io/asn1playground/
Base64 Encoder/Decoder: https://www.base64encode.org/