chore(letsencrypt): create valid certificates

This commit is contained in:
Michele Cereda
2024-05-08 18:46:32 +02:00
parent 21d2c1865c
commit 81d263417b
20 changed files with 3477 additions and 6 deletions

View File

@@ -0,0 +1,95 @@
---
- name: Create and validate an HTTPS certificate
hosts: all
vars:
common_name: service.example.org
pre_tasks:
- name: Generate private keys for an account and the certificate
community.crypto.openssl_privatekey:
path: "{{ item }}"
type: RSA
size: 4096
with_items:
- /tmp/{{ common_name }}.key
- /tmp/letsencrypt.account.key.pem
# - name: Generate private keys for an account and the certificate - OpenSSH alternative
# community.crypto.openssh_keypair:
# path: "{{ item }}"
# type: rsa
# size: 4096
# with_items:
# - /tmp/{{ common_name }}.key
# - /tmp/letsencrypt.account.key.pem
tasks:
- name: Generate the CRS for the certificate
community.crypto.openssl_csr:
path: /tmp/{{ common_name }}.crs
privatekey_path: /tmp/{{ common_name }}.key
common_name: "{{ common_name }}"
- name: Create the DNS challenge for '{{ common_name }}'
community.crypto.acme_certificate:
challenge: dns-01
acme_version: 2
acme_directory: https://acme-v02.api.letsencrypt.org/directory
account_key_src: /tmp/letsencrypt.account.key.pem
account_email: someone@example.org
csr: /tmp/{{ common_name }}.crs
cert: /tmp/{{ common_name }}.crt
terms_agreed: true
remaining_days: 21
register: dns_challenge
notify: Create TXT records for challenge validation
handlers:
- name: Create TXT records for challenge validation
when: common_name in dns_challenge.challenge_data
amazon.aws.route53:
zone: example.org
record: "{{ dns_challenge.challenge_data[common_name]['dns-01'].record }}"
type: TXT
ttl: 60
state: present
overwrite: true
wait: true
value:
# Value should be enclosed in quotation marks
>-
{{
dns_challenge.challenge_data[common_name]['dns-01'].resource_value
| regex_replace('^(.*)$', '"\1"')
}}
notify: Validate the challenge and create the certificate
- name: Validate the challenge and create the certificate
community.crypto.acme_certificate:
challenge: dns-01
acme_version: 2
acme_directory: https://acme-v02.api.letsencrypt.org/directory
account_key_src: /tmp/letsencrypt.account.key.pem
account_email: someone@example.org
csr: /tmp/{{ common_name }}.crs
cert: /tmp/{{ common_name }}.crt
remaining_days: 21
terms_agreed: true
data: "{{ dns_challenge }}"
post_tasks:
- name: Delete TXT records for challenge validation
vars:
validation_record: "{{ ['_acme-challenge', common_name] | join('.') }}"
when: query('community.dns.lookup', validation_record, type='TXT') != []
amazon.aws.route53:
zone: example.org
record: "{{ validation_record }}"
type: TXT
state: absent
wait: true

View File

@@ -0,0 +1 @@
export PULUMI_CONFIG_PASSPHRASE=test123

View File

@@ -0,0 +1 @@
set -x 'PULUMI_CONFIG_PASSPHRASE' 'test123'

View File

@@ -0,0 +1,2 @@
/bin/
/node_modules/

View File

@@ -0,0 +1,4 @@
encryptionsalt: v1:rsWIsa8WSik=:v1:D517hSFtoEVILMBz:wB9tX0Bu0Y0WqsXEYenywicAjnTHJw==
config:
acme:serverUrl: https://acme-v02.api.letsencrypt.org/directory

View File

@@ -0,0 +1,9 @@
name: letsencrypt-certificate.dns01
runtime: nodejs
description: DNS01 challenge with ACME leveraging Let's Encrypt
config:
pulumi:tags:
value:
pulumi:template: typescript
backend:
url: file://.

View File

@@ -0,0 +1,82 @@
import * as acme from '@pulumiverse/acme';
import * as cloudinit from "@pulumi/cloudinit";
import * as pulumi from "@pulumi/pulumi";
import * as tls from "@pulumi/tls";
import * as yaml from "yaml";
/**
* LetsEncrypt certificate - start
* -------------------------------------
* Leverage the DNS challenge to keep the instance private at all times.
**/
const privateKey = new tls.PrivateKey(
"privateKey",
{ algorithm: "RSA" },
);
const registration = new acme.Registration(
"registration",
{
accountKeyPem: privateKey.privateKeyPem,
emailAddress: "example@company.com",
},
);
const certificate = new acme.Certificate(
"certificate",
{
accountKeyPem: registration.accountKeyPem,
commonName: "gitlab.company.com",
dnsChallenges: [{
provider: "route53",
}],
},
);
/* LetsEncrypt certificate - end */
/**
* Instance - start
* -------------------------------------
* https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux#722646
**/
const userData = new cloudinit.Config(
"cloudConfig",
{
gzip: true,
base64Encode: true,
parts: [
{
contentType: "text/cloud-config",
content: pulumi.all([
certificate.certificateDomain.apply(v => v),
certificate.certificatePem.apply(v => v),
certificate.privateKeyPem.apply(v => v),
]).apply(([domain, certificate, privateKey]) => yaml.stringify({
write_files: [
{
path: `/etc/pki/tls/certs/${domain}.crt`,
content: btoa(certificate),
permissions: "0o600",
encoding: "base64",
defer: true,
},
{
path: `/etc/pki/tls/private/${domain}.key`,
content: btoa(privateKey),
permissions: "0o600",
encoding: "base64",
defer: true,
},
],
})),
filename: "cloud-config.letsencrypt.certificate.yml",
mergeType: "dict(recurse_array,no_replace)+list(append)",
},
],
},
);
/* Instance - end */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
{
"name": "letsencrypt-certificate.dns01",
"main": "index.ts",
"devDependencies": {
"@types/node": "^18"
},
"dependencies": {
"@pulumi/cloudinit": "1.4.3",
"@pulumi/pulumi": "3.115.2",
"@pulumi/tls": "5.0.3",
"@pulumiverse/acme": "0.0.1",
"yaml": "2.4.2"
}
}

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"outDir": "bin",
"target": "es2020",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.ts"
]
}