How to create Root CA and Intermediate CA in AWS ACM PCA to issue private certificates
Matheus Almeida Costa
Posted on May 6, 2024
The purpose of this post is to show how to create an external root CA and an intermediate CA using AWS Private CA to be able to issue private certificates in AWS.
To generate the certificates, you will need to use the openssl
tool, if it is not installed, use the following command to install:
sudo apt install openssl
# or
sudo yum install openssl
Create a local environment for creating the certificate components:
mkdir ca
touch ca/root-openssl.cnf
touch ca/intermediate-ext.cnf
touch ca/intermediate-request.csr
cd ca
Create external root certificate
First, we must create the custom openssl configuration file to generate the certificate with the appropriate information and the extensions.
The extensions will define the usefulness of the certificate, for more information about these extensions I recommend reading the official openssl documentation.
1. Fill the root-openssl.cnf
file with the content:
[ req ]
distinguished_name = req_distinguished_name
policy = policy_match
x509_extensions = v3_ca
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = BR
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = State
localityName = Locality Name (eg, city)
localityName_default = City
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Organization
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Organizational Unit
commonName = Common Name (eg, your name or your server hostname)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign,digitalSignature,cRLSign
2. Generate password to encrypt private key
openssl rand -base64 32 > root-password-encrypted.txt
The command will generate 32 random characters to create a password that will be used to encrypt the private key.
3. Generate the encrypted private key
openssl genrsa -aes256 -out root-encrypted.key -passout file:root-password-encrypted.txt 4096
The command will generate a 4096-bit encrypted RSA private key using the AES256 encryption algorithm.
4. Generate the root CA certificate
openssl req -new -x509 -days 7300 -config root-openssl.cnf -key root-encrypted.key -passin file:root-password-encrypted.txt -out root-certificate.pem
The command will generate the self-signed root certificate based on the decrypted private key with an expiration time of 20 years (7300 days).
When executing the command, you will be asked to fill in the certificate information such as CN, OU, etc.
We can use the command below to view the certificate content in plain text:
openssl x509 -in root-certificate.pem -text -noout
The output of this command will look like:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
70:5a:46:4a:85:a6:20:51:4b:21:47:dc:1e:4a:d5:98:a9:c6:4b:d2
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = BR, ST = Minas Gerais, L = Belo Horizonte, O = Me, OU = Me, CN = Root CA
Validity
Not Before: May 5 19:05:30 2024 GMT
Not After : Apr 30 19:05:30 2044 GMT
Subject: C = BR, ST = Minas Gerais, L = Belo Horizonte, O = Me, OU = Me, CN = Root CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (4096 bit)
Modulus:
00:c4:04:99:9e:f9:aa:13:02:b5:8e:19:49:44:77:
8c:4d:89:c6:0b:86:6b:6e:51:d7:0b:38:e2:69:aa:
f2:2c:ff:21:fd:b1:8b:f2:65:d9:0c:69:a2:f6:b0:
53:7c:92:9a:6d:ed:8a:3d:ce:6a:9d:2f:92:c4:17:
df:83:ef:a1:37:4d:c0:22:bd:85:55:7a:bd:81:a7:
02:31:50:08:49:ec:40:00:46:3c:16:ed:54:d8:9e:
db:9b:03:d8:75:e9:0d:54:81:da:de:98:87:aa:6c:
87:b8:fe:98:5f:d8:8d:22:a1:86:3d:03:ad:32:3d:
61:8e:bb:32:75:78:2a:e8:a7:4a:27:93:2b:09:de:
0a:f5:e2:4f:ae:d1:88:0e:11:42:82:da:31:ab:4c:
45:db:a6:60:c8:54:a0:6b:79:79:77:73:ad:e4:79:
7e:66:58:eb:a9:eb:9a:28:89:bf:85:76:93:42:53:
8c:f9:8b:d3:a5:88:aa:db:d9:ab:b6:82:76:f9:fd:
76:06:17:41:16:de:83:94:60:5c:d7:96:cd:87:76:
20:22:52:e1:6b:dc:f6:d1:b5:76:b3:01:03:7c:a0:
36:d4:d1:5b:e8:14:1a:60:e2:26:71:89:fc:aa:c8:
d9:25:66:0e:72:7b:5a:5d:02:86:11:05:44:0f:d2:
09:8e:51:34:0d:85:58:e2:e6:9e:ad:4e:04:1f:c0:
8b:0a:44:9a:b0:73:a2:0c:fc:1c:61:51:04:70:47:
7f:d2:d3:bd:b1:ce:8f:26:63:9c:63:8a:73:6a:e4:
7b:29:19:b6:1f:e1:3e:18:a0:a3:c9:75:46:06:f0:
06:85:e0:4d:87:03:84:b1:11:ba:c0:50:f9:ac:dd:
29:ff:c2:94:c5:59:02:61:37:c1:f2:0c:79:5d:ef:
96:7d:a8:ab:e3:c8:94:05:a1:e0:19:4a:3b:ad:37:
db:02:51:39:fa:0d:96:c3:88:d7:98:9c:6d:5e:62:
11:4f:44:58:26:1b:3c:5c:56:58:b4:f2:65:08:f4:
02:b8:11:44:76:01:62:b7:76:e7:fd:de:f4:3f:c9:
02:1f:e1:95:71:03:12:26:d0:78:23:0c:53:35:1d:
fd:9b:45:37:8e:46:96:f5:66:d4:a4:b5:36:79:d6:
50:0c:f1:e3:89:b4:79:32:09:5e:11:72:5c:65:34:
6c:9c:a3:45:8a:a7:04:6f:c7:88:d8:ac:93:ec:e9:
57:62:a3:9a:de:43:d9:72:63:40:c1:7b:dc:ba:cf:
2f:35:db:70:68:ed:1c:c6:78:89:8b:f4:29:da:e4:
79:4a:27:38:71:d8:61:4a:f9:dd:5f:8f:33:45:f4:
40:20:bd
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
61:51:2D:F8:F0:95:C5:FF:FE:96:A8:2C:E0:85:ED:58:E5:7F:0A:84
X509v3 Authority Key Identifier:
keyid:61:51:2D:F8:F0:95:C5:FF:FE:96:A8:2C:E0:85:ED:58:E5:7F:0A:84
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption
41:91:9e:85:54:bd:44:49:86:94:4c:d4:fb:8b:9e:c3:32:4f:
6d:a3:8f:ea:e4:0f:b0:a2:97:24:56:64:3a:e6:99:15:2f:31:
96:6c:ed:6f:cf:0a:8d:f8:1c:38:db:41:86:64:22:52:19:fd:
3b:ff:22:92:37:f8:05:6e:0a:7c:f2:4b:ba:4c:5f:bf:5b:18:
8f:f5:38:0c:22:49:15:de:17:99:e1:c5:69:3a:0f:d9:18:4d:
c0:c5:6e:ff:32:35:df:e1:7e:c1:e7:0f:7f:b6:ed:a6:e2:0d:
2f:cd:29:65:14:94:3d:90:79:e5:a7:3e:93:a6:d4:92:2a:b6:
62:9f:41:20:ed:23:80:28:3d:80:cd:d4:47:bd:06:d3:6e:35:
c9:28:6e:21:87:c7:72:39:c4:1c:66:fa:21:c2:73:f6:dd:ba:
16:99:84:11:fb:91:f0:40:17:38:5a:24:c1:d2:2d:8d:be:76:
34:05:95:f0:f3:bf:b2:5b:26:05:d1:28:5f:b8:e2:cb:db:d7:
79:29:fe:8e:c5:4e:ac:97:55:f0:fd:37:42:f3:f0:23:27:f9:
24:b4:92:f0:d0:23:63:10:52:82:55:61:fe:7a:c4:5f:5b:a8:
7c:88:16:e2:8e:f1:72:bf:56:8b:23:c4:93:5b:3b:4b:d5:e9:
e1:f4:bb:26:d4:2c:32:7c:f7:6a:a9:f3:42:21:a3:f4:5b:d3:
f1:59:74:67:13:59:e6:81:3c:88:a2:2a:3a:25:b3:df:b2:b9:
fd:b3:95:36:f4:18:bf:a1:51:b6:1d:c8:03:cc:a2:e6:2b:99:
bb:36:68:48:88:96:31:f0:db:7f:f0:48:57:da:bc:dd:f4:f6:
53:1b:57:7a:5f:16:ab:1b:f5:ff:a0:96:30:5f:8d:57:b5:b0:
7c:f2:a2:40:27:6d:e6:20:5f:13:79:3c:5b:ac:5d:78:40:59:
24:e2:91:5f:ac:e1:f2:c0:b7:87:b7:d0:66:78:06:6e:1b:77:
b3:64:2d:62:14:e1:ec:cf:c3:2a:cb:38:08:87:04:11:ca:03:
e6:a8:e1:4e:c4:13:ad:9b:ed:15:80:58:44:81:50:17:cf:ae:
84:32:0c:b3:fc:89:93:db:9c:a1:56:7c:a0:5a:f9:37:7e:a0:
81:dd:48:b4:a4:40:25:95:17:f3:00:0f:72:4d:9f:ca:9e:e0:
c0:a1:d4:58:67:21:11:29:4c:97:0d:c6:38:db:c5:f8:80:98:
1b:77:12:7c:7e:0c:bc:cc:11:d7:79:7e:45:d5:69:ae:5c:6d:
a6:8a:a9:6c:c2:22:90:0d:74:a4:c5:af:56:72:cd:46:38:40:
32:a9:05:29:5b:28:b9:fd
Create Intermediate Certificate in AWS Private CA
Now that we have our external root CA, the idea is to use it to sign the intermediate (subordinate) CA that we will create in AWS Private CA, this intermediate CA will be responsible for issuing the certificates for end use.
Note 1: Creating a CA on AWS has a cost of 400 dollars per month, but for the first CA the cost is minimal in the first month.
Note 2: The CA's private key is only stored in AWS, which is a security advantage as there is no risk of it being leaked and having to be revoked, on the other hand there is no way to export it .
To generate an intermediate CA, you must first generate your certificate signing request (CSR) so that it can be signed by the root CA.
In AWS Private CA we select the subordinate type and fill in the certificate information, just as we did to generate the root CA, we normally fill in the same information for both with the exception of the Common Name (CN) field.
In addition, we must select the type of private key algorithm (RSA or ECDSA) and optionally the certificate revocation configuration via CRL or OCSP.
Once this is done, it will generate a new arn for this AWS resource and will be in Pending Certificate status, because the request to generate the certificate (CSR) has been created but has not yet been signed by a root CA to issue the certificate for this intermediate CA.
To sign the CSR with our external root, we must select the resource and go to the "Install CA certificate" option.
We then select whether this intermediate CA will be signed by a CA that already exists in the AWS PCA or whether it will be signed by an external CA, in our case it will be an external CA.
AWS will make a certificate signing request (CSR) available.
1. Copy the CSR content provided by AWS to the intermediate-request.csr
file
2. Fill the intermediate-openssl.cnf
file with the following content:
[ intermediate_ca_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
basicConstraints = critical,CA:true,pathlen:0
keyUsage = critical,keyCertSign,digitalSignature,cRLSign
3. Generate the intermediate CA certificate
openssl x509 -req -days 3650 -extfile intermediate-openssl.cnf -extensions intermediate_ca_ext -in intermediate-request.csr -CA root-certificate.pem -CAkey root-encrypted.key -passin file:root-password-encrypted.txt -CAcreateserial -out intermediate-certificate.pem
To issue the certificate, we are based on the signature request (CSR) information made available by AWS intermediate-request.csr
signed by the root CA root-certificate.pem
and its encrypted private key root-encrypted.key
along with the password to decrypt it root-password-encrypted.txt
.
We also pass the extension settings for this intermediate certificate based on the intermediate_ca_ext
profile in the intermediate-openssl.cnf
file, in addition to the number of days that the certificate will be valid, in this case 10 years (3650 days).
Also set the random serial number creation using the -CAcreateserial
argument and thus generate the intermediate CA certificate intermediate-certificate.pem
.
With the certificate generated, simply import the respective fields directly into AWS Private CA:
- Certificate body: Certificate of the intermediate CA
intermediate-certificate.pem
. - Certificate chain: Root CA certificate
root-certificate.pem
.
With the certificates imported, select the "Install CA" option.
This way we will have a certification authority (CA) chain to issue private certificates on AWS via ACM.
Posted on May 6, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.