When companies are moving to the cloud, there is a real concern about securing the workloads. Part of a defense-in-depth strategy is a network firewall layer. Oracle Cloud Infrastructure delivers Network Firewall Service as part of the cloud offering.
As a good practice, the web applications are protected by SSL/TLS which creates an encrypted tunnel between the client and the server. This encryption "blinds" a stateful firewall and disables the intrusion detection capabilities of the firewall. As a mitigation technique, the firewall acts as a man-in-the-middle for the encrypted traffic and there are two different implementations for this:
In this post, I will cover the Inbound SSL decryption in the OCI Network Firewall when the server is using an RSA public certificate issued by let's Encrypt.
For implementing this Inbound inspection of the traffic on the Network Firewall, you need an SSL/TLS certificate. In this post, I will use an RSA certificate issued by let'e Encrypt. If you do not have a certificate, you can generate a self-signed one, using this blog-post or you can generate a public certificate using this blog-post.
If you want to get familiar with the OCI Network Firewall Service, you can check out the official documentation and the blog that Troy wrote when the service was released. I would recommend reading this blog that explains the difference between the Network Firewall and the Web Application firewall. Inside this blog are references to other blogs that cover the use case of the service.
In this post, I will not cover the theory behind PKI infrastructure and how the network firewall acts as a bump in the wire for the traffic.
As a reference on how the SSL works and how the network firewall inspects the traffic, I would recommend reading this tutorial.
I started to create this blog, mainly because, the official documentation and the tutorial that I was sharing earlier, cover the inbound inspection when the certificates are self-signed and as a side note, the script used to generate the certificates will generate a server one with the CA:TRUE extension, which in my opinion, will never be used in a production scenario.
The SSL/TLS decryption relies on a secret containing the SSL/TLS certificates uploaded to the Vault service. The firewall will not store the certificates, it will only use them from the vault.
The secret needs to be in a JSON format and in order to prepare the file you need to have the needed certificates.
If you check a fullchain certificate from Let's Encrypt, you can observe that the first certificate in the chain is the server certificate, the second one is the intermediate certificate and the last one is the root certificate.
openssl crl2pkcs7 -nocrl -certfile fullchain.crt| openssl pkcs7 -print_certs -text -noout | grep 'Subject:\|Issuer:'
Issuer: C=US, O=Let's Encrypt, CN=R3
Subject: CN=*.ateam-oracle.cloud
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Subject: C=US, O=Let's Encrypt, CN=R3
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Subject: C=US, O=Internet Security Research Group, CN=ISRG Root X1
openssl crl2pkcs7 -nocrl -certfile fullchain.crt| openssl pkcs7 -print_certs -text -noout | grep 'Subject:\|Issuer:'
Issuer: C=US, O=Let's Encrypt, CN=R3
Subject: CN=*.ateam-oracle.cloud
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Subject: C=US, O=Let's Encrypt, CN=R3
Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1
Subject: C=US, O=Internet Security Research Group, CN=ISRG Root X1
To make life easier and to identify which certificate is which (in cases where there are multiple intermediate CAs) I am using the following command:
openssl crl2pkcs7 -nocrl -certfile fullchain.crt |openssl pkcs7 -print_certs -out individual-certs.pem
openssl crl2pkcs7 -nocrl -certfile fullchain.crt |openssl pkcs7 -print_certs -out individual-certs.pem
This will put the "subject" and the "issuer" before each certificate.
subject=/CN=*.ateam-oracle.cloud
issuer=/C=US/O=Let's Encrypt/CN=R3
-----BEGIN CERTIFICATE-----
MIIF9DCCBNygAwIBAgISA3Dez7UxteTcwWxX59wPU+HjMA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMzA5MjgxNzQ5MjNaFw0yMzEyMjcxNzQ5MjJaMB8xHTAbBgNVBAMM
FCouYXRlYW0tb3JhY2xlLmNsb3VkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
subject=/CN=*.ateam-oracle.cloud
issuer=/C=US/O=Let's Encrypt/CN=R3
-----BEGIN CERTIFICATE-----
MIIF9DCCBNygAwIBAgISA3Dez7UxteTcwWxX59wPU+HjMA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMzA5MjgxNzQ5MjNaFw0yMzEyMjcxNzQ5MjJaMB8xHTAbBgNVBAMM
FCouYXRlYW0tb3JhY2xlLmNsb3VkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
From this file I will extract individual certificates and I will name them: root-X1.crt, intermediate-R3.crt. The certificate for the server and the private key I already had them when i generated the certificate.
With all these file in one directory, we need to create the secret that will be stored in the vault. Follow this documentation to create the secret.
At Task 3 in the documentation, there is sample format for the secret that will be stored in the vault.
{
"caCertOrderedList" : [
"ROOT_CERT01_PEM_CONTENT",
"INTERMEDIATE_CERT01_PEM_CONTENT",
"INTERMEDIATE_CERT02_PEM_CONTENT",
],
"certKeyPair": {
"cert" : "LEAF_CERT_01_PEM_CONTENT",
"key": "PRIVATE_KEY_01_PEM_CONTENT"
}
}
{
"caCertOrderedList" : [
"ROOT_CERT01_PEM_CONTENT",
"INTERMEDIATE_CERT01_PEM_CONTENT",
"INTERMEDIATE_CERT02_PEM_CONTENT",
],
"certKeyPair": {
"cert" : "LEAF_CERT_01_PEM_CONTENT",
"key": "PRIVATE_KEY_01_PEM_CONTENT"
}
}
At the time of writing this post, following the sample format will result in errors at 44% when applying the policy to the firewall. the issue is the comma after the "INTERMEDIATE_CERT02_PEM_CONTENT". If you remove it, you will not have any problems.
I created a little bash script to make our life easier when creating the json file:
#!/bin/bash
cat > ateam.ssl-inbound-inspection.json << EOF
{
"caCertOrderedList" : [
"$(perl -pe 's/\n/\\n/' <replace with the path to>/root-X1.crt)",
"$(perl -pe 's/\n/\\n/' <replace with the path to>/intermediate-R3.crt)"
],
"certKeyPair": {
"cert" : "$(perl -pe 's/\n/\\n/' <replace with the path to>/star.ateam-oracle.crt)",
"key": "$(perl -pe 's/\n/\\n/' <replace with the path to>/star.ateam-oracle.key)"
}
}
EOF
#!/bin/bash
cat > ateam.ssl-inbound-inspection.json << EOF
{
"caCertOrderedList" : [
"$(perl -pe 's/\n/\\n/' <replace with="" the="" path="" to="">/root-X1.crt)",
"$(perl -pe 's/\n/\\n/' <replace with="" the="" path="" to="">/intermediate-R3.crt)"
],
"certKeyPair": {
"cert" : "$(perl -pe 's/\n/\\n/' <replace with="" the="" path="" to="">/star.ateam-oracle.crt)",
"key": "$(perl -pe 's/\n/\\n/' <replace with="" the="" path="" to="">/star.ateam-oracle.key)"
}
}
EOF</replace></replace></replace></replace>
First we need to have a vault, navigate to Identity and Security
> Key Management & Secret Management
> Vault
and create a vault.
Under the vault, create a Master Encryption Key.
Under Secrets, create a new one. Under the encryption key, select the key that was previously created and in the Secrets Content, paste the JSON file that we created earlier.
Navigate to Identity & Security
> Firewalls
> Network firewall policies
and edit your policy.
Mapped secrets
add a new secret.Decryption Profiles
create a new profile.Navigate to Identity & Security
> Firewalls
> Network firewalls
and click on your firewall and hit the edit button.
Select the firewall policy and hit save changes.
Behind the Network Firewall, I have a Linux virtual machine where I installed a web server with TLS activates.
For testing purposes, I downloaded the eicar test file on the web server in the wwwroot folder and I tried to display that file by connecting from a customer web browser.
The network firewall stopped traffic, and we can see the details in the Threat log.
A normal connection to the website is permitted.
In this post, we showed the configuration needed for the Network Firewall to decrypt a SSL/TLS connection from a client from the Internet to a web server.