How to create Root CA and Intermediate CA in AWS ACM PCA to issue private certificates
Tags: aws, acm, ca, certificate
Published: 2024-05-06 02:20:22


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](https://medium.com/r?url=https%3A%2F%2Fwww.openssl.org%2Fdocs%2Fman3.0%2Fman5%2Fx509v3_config.html).

#### 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.

![Create subordinate CA](https://miro.medium.com/v2/format:webp/1*Zw1eA7dQmHdYlSUQCntiPw.jpeg)

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.

![Private CA created with status pending for installation](https://miro.medium.com/v2/format:webp/1*vgT8GEU6uKgnmZRHaO1dAA.jpeg)

To sign the CSR with our external root, we must select the resource and go to the *"Install CA certificate"* option.

![Install CA — sign intermediate CA with root CA](https://miro.medium.com/v2/format:webp/1*8NKzxEj49sCauE-BUPhTvQ.jpeg)

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.

![Issue the subordinate CA with the external root CA](https://miro.medium.com/v2/format:webp/1*rI_467TfcXc-_PR-Lw_p5w.jpeg)

AWS will make a certificate signing request (CSR) available.

![CA CSR issued by AWS](https://miro.medium.com/v2/format:webp/1*p6Zb0bv7dM4flqxX2FMc1Q.jpeg)

#### 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`.

![Import the certificate body and chain](https://cdn-images-1.medium.com/v2/resize:fit:880/1*l5agdqJn5gRQxD59AGfQnQ.jpeg)

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.