{"id":5077,"date":"2023-07-05T10:25:15","date_gmt":"2023-07-05T08:25:15","guid":{"rendered":"https:\/\/promatis.com\/ch\/oracle-oci-load-balancer-with-lets-encrypt-free-ssl-certificates\/"},"modified":"2023-07-05T10:27:57","modified_gmt":"2023-07-05T08:27:57","slug":"oracle-oci-load-balancer-with-lets-encrypt-free-ssl-certificates","status":"publish","type":"post","link":"https:\/\/promatis-test.de\/ch\/oracle-oci-load-balancer-with-lets-encrypt-free-ssl-certificates\/","title":{"rendered":"Oracle OCI Load Balancer with Lets Encrypt (free) SSL certificates"},"content":{"rendered":"

[et_pb_section fb_built=\"1\" custom_padding_last_edited=\"on|tablet\" disabled_on=\"off|off|off\" admin_label=\"Sektion\" _builder_version=\"4.17.6\" _module_preset=\"default\" custom_padding=\"5vh||5vh||true|false\" custom_padding_tablet=\"5vh||5vh||true|false\" custom_padding_phone=\"5vh||5vh||true|false\" global_module=\"23\" locked=\"off\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_row column_structure=\"1_4,3_4\" _builder_version=\"4.17.6\" _module_preset=\"default\" custom_margin=\"||0px||false|false\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_column type=\"1_4\" _builder_version=\"4.17.6\" _module_preset=\"default\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_image src=\"https:\/\/promatis.com\/wp-content\/uploads\/2022\/07\/johannes-michler.png\" alt=\"Johannes Michler PROMATIS Horus Oracle\" title_text=\"johannes-michler\" _builder_version=\"4.20.2\" _module_preset=\"default\" width=\"90%\" custom_margin=\"0vh||0vh||true|false\" border_radii=\"on|516px|516px|516px|516px\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][\/et_pb_image][\/et_pb_column][et_pb_column type=\"3_4\" _builder_version=\"4.17.6\" _module_preset=\"default\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_text ul_type=\"square\" _builder_version=\"4.20.2\" _module_preset=\"default\" text_font=\"Open Sans||||||||\" text_font_size=\"17px\" text_line_height=\"1.6em\" link_font=\"Open Sans||||on|||gcid-0becd5ff-19fc-4653-a221-c8c75771a987|\" link_text_color=\"gcid-0becd5ff-19fc-4653-a221-c8c75771a987\" link_font_size=\"22px\" ul_font=\"Open Sans||||||||\" ul_font_size=\"17px\" ul_line_height=\"1.6em\" header_font=\"|600||on|||||\" header_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_font_size=\"47px\" header_line_height=\"1.2em\" header_2_font=\"|600||on|||||\" header_2_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_2_line_height=\"1.6em\" header_3_font=\"|600|||||||\" header_3_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_3_font_size=\"24px\" header_3_line_height=\"1.4em\" header_4_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_4_line_height=\"1.4em\" header_5_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_5_line_height=\"1.4em\" header_6_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_6_font_size=\"16px\" header_6_line_height=\"1.4em\" custom_margin=\"2vh||0px||false|false\" custom_padding=\"||||true|false\" text_font_size_tablet=\"20px\" text_font_size_phone=\"17px\" text_font_size_last_edited=\"on|tablet\" header_font_size_tablet=\"\" header_font_size_phone=\"28px\" header_font_size_last_edited=\"on|phone\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22%93,%22gcid-0becd5ff-19fc-4653-a221-c8c75771a987%22:%91%22link_text_color%22%93}\" theme_builder_area=\"post_content\"]<\/p>\n

Johannes Michler<\/a><\/div>\n

[\/et_pb_text][et_pb_text ul_type=\"square\" _builder_version=\"4.20.0\" _module_preset=\"default\" text_font=\"Open Sans||||||||\" text_font_size=\"17px\" text_line_height=\"1.6em\" link_font=\"Open Sans||||on||||\" link_text_color=\"#00A9A0\" ul_font=\"Open Sans||||||||\" ul_font_size=\"17px\" ul_line_height=\"1.6em\" header_font=\"|600||on|||||\" header_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_font_size=\"47px\" header_line_height=\"1.2em\" header_2_font=\"|600||on|||||\" header_2_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_2_line_height=\"1.6em\" header_3_font=\"|600|||||||\" header_3_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_3_font_size=\"24px\" header_3_line_height=\"1.4em\" header_4_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_4_line_height=\"1.4em\" header_5_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_5_line_height=\"1.4em\" header_6_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_6_font_size=\"16px\" header_6_line_height=\"1.4em\" custom_margin=\"1vh||0px||false|false\" custom_padding=\"||||true|false\" text_font_size_tablet=\"20px\" text_font_size_phone=\"17px\" text_font_size_last_edited=\"on|tablet\" header_font_size_tablet=\"\" header_font_size_phone=\"28px\" header_font_size_last_edited=\"on|phone\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22%93}\" theme_builder_area=\"post_content\"]<\/p>\n


Executive Vice President<\/strong> \u2013\u00a0Head of Platforms\u00a0&\u00a0Development<\/p>\n

[\/et_pb_text][et_pb_text ul_type=\"square\" _builder_version=\"4.20.0\" _module_preset=\"default\" text_font=\"Open Sans||||||||\" text_text_color=\"gcid-0becd5ff-19fc-4653-a221-c8c75771a987\" text_font_size=\"22px\" text_line_height=\"1.6em\" link_font=\"Open Sans||||on||||\" link_text_color=\"#00A9A0\" ul_font=\"Open Sans||||||||\" ul_font_size=\"17px\" ul_line_height=\"1.6em\" header_font=\"|600||on|||||\" header_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_font_size=\"47px\" header_line_height=\"1.2em\" header_2_font=\"|600||on|||||\" header_2_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_2_line_height=\"1.6em\" header_3_font=\"|600|||||||\" header_3_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_3_font_size=\"24px\" header_3_line_height=\"1.4em\" header_4_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_4_line_height=\"1.4em\" header_5_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_5_line_height=\"1.4em\" header_6_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_6_font_size=\"16px\" header_6_line_height=\"1.4em\" custom_margin=\"5px||0px||false|false\" custom_padding=\"||||true|false\" text_font_size_tablet=\"20px\" text_font_size_phone=\"17px\" text_font_size_last_edited=\"on|tablet\" header_font_size_tablet=\"\" header_font_size_phone=\"28px\" header_font_size_last_edited=\"on|phone\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22%93,%22gcid-0becd5ff-19fc-4653-a221-c8c75771a987%22:%91%22text_text_color%22%93}\" theme_builder_area=\"post_content\"]<\/i><\/a><\/i><\/a><\/i><\/a>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=\"1\" _builder_version=\"4.16\" _module_preset=\"default\" custom_padding=\"0vh||10vh||false|false\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_row use_custom_gutter=\"on\" _builder_version=\"4.17.3\" _module_preset=\"default\" custom_padding=\"0px||0px||true|false\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_column type=\"4_4\" _builder_version=\"4.16\" _module_preset=\"default\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_text _builder_version=\"4.21.0\" _module_preset=\"default\" background_enable_color=\"off\" custom_padding=\"0px||0px||true|false\" inline_fonts=\"Times New Roman\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22%93,%22gcid-0becd5ff-19fc-4653-a221-c8c75771a987%22:%91%22background_color%22%93}\" theme_builder_area=\"post_content\"]<\/p>\n

\"\"
E-Business Suite Umgebung mit LetsEncrypt Zertifikat<\/em><\/p>\n

Nowadays, all web traffic through the internet should be encrypted. For this to work, SSL certificates are required. These can be bought from commercial Certificate Authorities. Since around 2016, certificates are also provided for free by the nonprofit Certificate Authority Let's Encrypt. There are various tools to create these certificates, also with Oracle OCI, however, they usually require dedicated web servers for verification with a HTTP challenge or they need control over DNS. This blog post will show a very lightweight alternative using OCI Load Balancer, OCI Object Storage as well as the OCI Certificate Service.<\/p>\n

Basic setup in OCI<\/h2>\n

First of all you have to create a new OCI Object Storage bucket (let's name it \"acme\") and make it \"publicly\" visible. Into this bucket, we put a dummy file acmetoken.txt:<\/p>\n

\"\"<\/p>\n

Public Object Storage Bucket with dummy file<\/em><\/p>\n

Note down the Object Storage namespace which is part of the URL of the file.<\/p>\n

Then, we create an empty \"rule set\" (we name it acme) in the Load Balancer that we want to generate SSL certificates for:<\/p>\n

\"\"<\/p>\n

OCI Load Balancer Rule set \"acme\"<\/em><\/p>\n

We then have to assign that rule set to a listener (an existing one or a new one, if you use exclusively HTTPS for regular traffic as I do in the following case):<\/p>\n

\"\"<\/p>\n

Dummy listener on Port 80 that is used only for SSL certificate generation<\/em><\/p>\n

Note that it is NOT necessary to have a dedicated listener for that, since we will later only \"intercept\" the ACME challenge you can easily add it to an existing (HTTP) listener.<\/p>\n

If you do not allow regular public internet traffic to port 80 (as I do in this case), you need to create a special security list \"letsencrypt\" and assign it to the Load Balancer subnet:<\/p>\n

\"\"<\/p>\n

(Usually) empty security list to be assigned to the Load Balancer subnet<\/em><\/p>\n

Note down the OCIDs of the Load Balancer, the security list as well as the compartment where you want to store the certificates.<\/p>\n

Install certbot<\/h2>\n

You need to run certbot on an instance where you have OCI Command Line tools as well as a recent python3. I in my case use the E-Business Suite Cloud Manager VM for that purpose.<\/p>\n

There, install certbot into a virtual environment as follows:<\/p>\n

python3 -m venv \/u01\/install\/APPS\/certbot\n\/u01\/install\/APPS\/certbot\/bin\/pip install --upgrade pip\n\/u01\/install\/APPS\/certbot\/bin\/pip install certbot certbot\nmkdir \/u01\/install\/APPS\/certbot\/log\nmkdir \/u01\/install\/APPS\/certbot\/config\nmkdir \/u01\/install\/APPS\/certbot\/work<\/pre>\n

Create scripts for OCI interaction<\/h2>\n

Furthermore, create a oci-authenticator.sh in that folder (enter OCID_LB and OCID_SECLIST of your case):<\/p>\n

#!\/bin\/bash\nCONFIG_FILE=\/u01\/install\/APPS\/.oci\/johannes.michler@promatis.de\nOCID_LB=ocid1.loadbalancer.oc1.eu-frankfurt-1.XXXXX\nOCID_SECLIST=ocid1.securitylist.oc1.eu-frankfurt-1.YYYYY\necho CERTBOT_TOKEN $CERTBOT_TOKEN\necho CERTBOT_VALIDATION $CERTBOT_VALIDATION\noci --config-file $CONFIG_FILE network security-list update --security-list-id $OCID_SECLIST --ingress-security-rules '[{\"description\": \"temporaryLetsEncrypt\",\"icmp-options\": null,\"is-stateless\": false,\"protocol\": \"6\",\"source\": \"0.0.0.0\/0\",\"source-type\": \"CIDR_BLOCK\",\"tcp-options\": {\"destination-port-range\": {\"max\": 80,\"min\": 80},\"source-port-range\": null},\"udp-options\": null}]' --force --wait-for-state AVAILABLE\necho $CERTBOT_VALIDATION > acmetoken.txt\noci --config-file $CONFIG_FILE os object put --bucket-name acme --file acmetoken.txt --force\nACME_JSON=$(sed \"s\/THIS_IS_THE_CHALLENGE\/${CERTBOT_TOKEN}\/g\" acme.json)\noci --config-file $CONFIG_FILE lb rule-set update --load-balancer-id $OCID_LB --rule-set-name acme --force --items \"$ACME_JSON\" --wait-for-state SUCCEEDED\nwget -q -O - >http:\/\/${CERTBOT_DOMAIN}\/.well-known\/acme-challenge\/${CERTBOT_TOKEN}<\/pre>\n

You can skip the first oci command if it is not necessary to open the network security-list.<\/p>\n

And an acme.json as follows, where you have to replace with the Object Storage namespace:<\/replace_with_osurl><\/p>\n

[\n      {\n        \"action\": \"REDIRECT\",\n        \"conditions\": [\n          {\n            \"attribute-name\": \"PATH\",\n            \"attribute-value\": \"\/.well-known\/acme-challenge\/THIS_IS_THE_CHALLENGE\",\n            \"operator\": \"EXACT_MATCH\"\n          }\n        ],\n        \"redirect-uri\": {\n          \"host\": \"objectstorage.eu-frankfurt-1.oraclecloud.com\",\n          \"path\": \"\/n\/\/b\/acme\/o\/acmetoken.txt\",\n          \"port\": 443,\n          \"protocol\": \"https\",\n          \"query\": \"\"\n        },\n        \"response-code\": 302\n      }\n]<\/replace_with_osurl><\/pre>\n

Create an oci-deploy.sh (fill in the COMPARTMENT_ID)<\/p>\n

#!\/bin\/bash\necho RENEWED_DOMAINS $RENEWED_DOMAINS\necho RENEWED_LINEAGE $RENEWED_LINEAGE\nCOMPARTMENT_ID=ocid1.compartment.oc1..ZZZZZZ\nCONFIG_FILE=\/u01\/install\/APPS\/.oci\/johannes.michler@promatis.de\nOCI_CERT_OCID=$(oci --config-file $CONFIG_FILE certs-mgmt certificate list --all --compartment-id $COMPARTMENT_ID --query \"data.items[?subject.\\\"common-name\\\"=='${RENEWED_DOMAINS}'].id|join(',',@)\"| tr -d '\\\"\"')\necho OCI_CERT_OCID $OCI_CERT_OCID\nCERT_PATH=$(cat $RENEWED_LINEAGE\/cert.pem)\nCERT_CHAIN=$(cat $RENEWED_LINEAGE\/chain.pem)\nCERT_KEY=$(cat $RENEWED_LINEAGE\/privkey.pem)\noci --config-file $CONFIG_FILE certs-mgmt certificate update-certificate-by-importing-config-details --certificate-id=$OCI_CERT_OCID --cert-chain-pem=\"$CERT_CHAIN\" --certificate-pem=\"$CERT_PATH\" --private-key-pem=\"$CERT_KEY\"<\/pre>\n

And finally, oci-closefirewall.sh (only if you need to open port 80; fill OCID of security list again):<\/p>\n

#!\/bin\/bash\nCONFIG_FILE=\/u01\/install\/APPS\/.oci\/johannes.michler@promatis.de\nOCID_SECLIST=ocid1.securitylist.oc1.eu-frankfurt-1.YYYYY\noci --config-file $CONFIG_FILE network security-list update --security-list-id $OCID_SECLIST --ingress-security-rules '[]' --force --wait-for-state AVAILABLE<\/pre>\n

Then, give execution privs to the user:<\/p>\n

chmod 755 \/u01\/install\/APPS\/certbot\/oci-authenticator.sh\nchmod 755 \/u01\/install\/APPS\/certbot\/oci-closefirewall.sh\nchmod 755 \/u01\/install\/APPS\/certbot\/oci-deploy.sh<\/pre>\n

Create Certificate<\/h2>\n

With those preparations completed, we can now request a first certificate:<\/p>\n

\/u01\/install\/APPS\/certbot\/bin\/certbot certonly \\\n--manual --preferred-challenges=http \\\n--manual-auth-hook \/u01\/install\/APPS\/certbot\/oci-authenticator.sh \\\n--manual-cleanup-hook \/u01\/install\/APPS\/certbot\/oci-closefirewall.sh \\\n--logs-dir \/u01\/install\/APPS\/certbot\/log \\\n--config-dir \/u01\/install\/APPS\/certbot\/config \\\n--work-dir \/u01\/install\/APPS\/certbot\/work \\\n-d XXXX_MYDOMAINNAME<\/pre>\n

This should, after some questions, give a result as follows:<\/p>\n

Successfully received certificate\nCertificate is saved at: \/u01\/install\/APPS\/certbot\/config\/live\/XXXX_MYDOMAINNAME\/fullchain.pem\nKey is saved at:         \/u01\/install\/APPS\/certbot\/config\/live\/XXXX_MYDOMAINNAME\/privkey.pem\nThis certificate expires on 2023-08-16.\nThese files will be updated when the certificate renews..<\/pre>\n

Install Certificate into Certificate Management Service<\/h2>\n

Got to the OCI Certificate Management Service and create a new \"Imported\" certificate testaebsapp.<\/p>\n

\"\"<\/p>\n

Letsencrypt Certificate Service<\/em><\/p>\n

In Step 3 upload cert.pem, chain.pem and privkey.pem created in the previous step. Finally, you can use the certificate uploaded in the OCI Load Balancer and receive a properly signed SSL certificate.<\/p>\n

Renew Certificates automatically<\/h2>\n

Let's encrypt certificates have a rather short lifetime. Luckily, the above process including the renewal of the certificate in the OCI Certificate Service can be easily automated with the following command:<\/p>\n

\/u01\/install\/APPS\/certbot\/bin\/certbot renew \\
--manual --preferred-challenges=http \\
--manual-auth-hook \/u01\/install\/APPS\/certbot\/oci-authenticator.sh \\
--manual-cleanup-hook \/u01\/install\/APPS\/certbot\/oci-closefirewall.sh \\
--logs-dir \/u01\/install\/APPS\/certbot\/log -\\
-config-dir \/u01\/install\/APPS\/certbot\/config \\
--work-dir \/u01\/install\/APPS\/certbot\/work \\
--deploy-hook \/u01\/install\/APPS\/certbot\/oci-deploy.sh<\/pre>\n

To test if everything is working, a renewal can be enforced by adding --force-renewal.<\/p>\n

Summary<\/h2>\n

The above procedure shows a very lightweight approach on how SSL certificates from letsencrypt can be created for use in OCI (e.g. Load Balancer) services.<\/p>\n

The approach described can also be used if you technically use the certificates for services that rely on internal hostnames and have a private IP assigned for XXXX_MYDOMAINNAME in the internal DNS server - as long as you assign a public IP in the public DNS for Let's Encrypt purposes. If you don't like this, I suggest you look into certbot-dns-oci<\/a>.<\/p>\n

[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"

Johannes MichlerExecutive Vice President \u2013\u00a0Head of Platforms\u00a0&\u00a0DevelopmentE-Business Suite Umgebung mit LetsEncrypt Zertifikat Nowadays, all web traffic through the internet should be encrypted. For this to work, SSL certificates are required. These can be bought from commercial Certificate Authorities. Since around 2016, certificates are also provided for free by the nonprofit Certificate Authority Let's Encrypt. There […]<\/p>\n","protected":false},"author":2,"featured_media":1243,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[23],"tags":[],"dipi_cpt_category":[],"class_list":["post-5077","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-techblog"],"_links":{"self":[{"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/posts\/5077"}],"collection":[{"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/comments?post=5077"}],"version-history":[{"count":0,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/posts\/5077\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/media\/1243"}],"wp:attachment":[{"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/media?parent=5077"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/categories?post=5077"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/tags?post=5077"},{"taxonomy":"dipi_cpt_category","embeddable":true,"href":"https:\/\/promatis-test.de\/ch\/wp-json\/wp\/v2\/dipi_cpt_category?post=5077"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}