Skip to content

Commit

Permalink
Revert "Remove certificate logic (#32)"
Browse files Browse the repository at this point in the history
This reverts commit a39e59e.
  • Loading branch information
dfangl authored Sep 4, 2024
1 parent a39e59e commit 8640bfd
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 0 deletions.
67 changes: 67 additions & 0 deletions .github/workflows/renew-certificate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Renew Certificate
on:
workflow_dispatch:
pull_request:
paths:
- ".github/workflows/renew-certificate.yml"
- "local-certs/certificate-domains"
- "local-certs/certificate-regions"
- "local-certs/generate-domains.py"
- "local-certs/generate-certificate.sh"
branches:
- master
push:
paths:
- ".github/workflows/renew-certificate.yml"
- "local-certs/certificate-domains"
- "local-certs/certificate-regions"
- "local-certs/generate-domains.py"
- "local-certs/generate-certificate.sh"
branches:
- master
schedule:
# * is a special character in YAML so you have to quote this string
- cron: '0 6 1 * *'

env:
git_user_name: localstack[bot]
git_user_email: [email protected]

permissions:
contents: write

jobs:
renew-certificate:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
id: setup-python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install Certbot
run: |
python -m pip install --upgrade pip wheel setuptools
pip install certbot certbot-plugin-gandi
- name: Generate certificate
working-directory: "local-certs"
env:
CERTBOT_ARGS: "${{ github.ref != 'refs/heads/master' && '--staging' || '' }}"
DNS_API_KEY: "${{ secrets.DNS_API_KEY }}"
CERTBOT_EMAIL: ${{ env.git_user_email }}
run: |
./generate-certificate.sh
- name: Commit certificate
working-directory: "local-certs"
if: github.ref == 'refs/heads/master'
run: |
git config user.name ${{ env.git_user_name }}
git config user.email ${{ env.git_user_email }}
git add server.key
expiry_date=$(date --date="$(openssl x509 -enddate -noout -in server.key | cut -d= -f 2)" --utc --iso-8601)
git commit -m "update local certificate keys (new expiry date: $expiry_date)"
git push
4 changes: 4 additions & 0 deletions local-certs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gandi.ini
config/
logs/
work/
20 changes: 20 additions & 0 deletions local-certs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Certificate renewal
The current certificate for `localhost.localstack.cloud` and several of its subdomains are stored in `server.key`.

The file contains both certificate and private key.

### Limitations
Please make sure to conform to the [LetsEncrypt Rate Limits](https://letsencrypt.org/docs/rate-limits/).

Most notably, do not rerequest the certficate for the same set of domain names more than 5 times a week, for new domain names more than 50 times a week and no more than 100 names in total per certificate.


### Domain lists

* `certificate-domains` contains a list (newline separated) with all domains the certificate should be valid for. It allows `{region}` as placeholder, to generate domains for multiple regions.
* `certificate-regions` contains a list (newline separated) of all regions which will be substituted for the `{region}` placeholder.


### Timeline

The certificate renewal will happen every time the domain/region list are updated, or every month.
15 changes: 15 additions & 0 deletions local-certs/certificate-domains
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
localhost.localstack.cloud
*.localhost.localstack.cloud
*.amplifyapp.localhost.localstack.cloud
*.cloudfront.localhost.localstack.cloud
*.elb.localhost.localstack.cloud
*.execute-api.localhost.localstack.cloud
*.opensearch.localhost.localstack.cloud
*.{region}.opensearch.localhost.localstack.cloud
*.s3-website.localhost.localstack.cloud
*.s3.localhost.localstack.cloud
*.scm.localhost.localstack.cloud
*.dkr.ecr.{region}.localhost.localstack.cloud
*.lambda-url.{region}.localhost.localstack.cloud
sqs.{region}.localhost.localstack.cloud
*.snowflake.localhost.localstack.cloud
6 changes: 6 additions & 0 deletions local-certs/certificate-regions
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
eu-central-1
eu-west-1
us-east-1
us-east-2
us-west-1
us-west-2
26 changes: 26 additions & 0 deletions local-certs/generate-certificate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash
set -euo pipefail

# generate comma separated list of all domains to request a cert for
certificate_domains=$(python generate-domains.py)
echo "Generating certificate for domains ${certificate_domains}"

# create credentials file
echo "dns_gandi_api_key=${DNS_API_KEY}" > gandi.ini
chmod 600 gandi.ini

# request certificate
set -x
certbot -n --agree-tos --email ${CERTBOT_EMAIL} ${CERTBOT_ARGS} --authenticator dns-gandi --dns-gandi-credentials gandi.ini --key-type rsa --work-dir=$PWD/work --config-dir=$PWD/config --logs-dir=$PWD/logs -d $certificate_domains certonly
set +x

# remove credentials to avoid accidental leakage
rm gandi.ini

# concatinate private key + cert into single file to match current structure
echo "Concatinating certificate and key into single file"
cat config/live/localhost.localstack.cloud/privkey.pem config/live/localhost.localstack.cloud/fullchain.pem > server.key

# display certificate information
echo "Certificate information"
openssl x509 -in server.key -text -noout
32 changes: 32 additions & 0 deletions local-certs/generate-domains.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python3

"""
This file generates a comma-separated list of domains,
by replacing the occurences of "{region}" in the domains
in "certificate-domains" by the regions in "certificate-regions"
"""


REGION_PLACEHOLDER = "{region}"


def generate_domains(domain_list: list[str], region_list: list[str]) -> list[str]:
result = []
for domain in domain_list:
if REGION_PLACEHOLDER in domain:
result += [domain.replace(REGION_PLACEHOLDER, region) for region in region_list]
else:
result.append(domain)
return result

def main():
with open("certificate-domains", mode="rt") as f:
domain_list = f.read().splitlines()
with open("certificate-regions", mode="rt") as f:
region_list = f.read().splitlines()
expanded_list = generate_domains(domain_list, region_list)
print(",".join(expanded_list), end="")


if __name__ == "__main__":
main()
119 changes: 119 additions & 0 deletions local-certs/server.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCkPpgky1WMi9DO
ujPv3icBhHTV/tKeAWl+7ZuM0BkQMhWHCz2MYtOCIbL1jbH41UOmKmNjHglbNO06
sxdWbMuwgpY/nE9fUEW3AYxsoK/PKB/IpJ4LmuCLeHt4RlqXG8BPeSX6UeTP08/8
yRToaZTgCNjrP30uk3FSQDIf6wsxKhQMM88MEQOQXkRGS0B7Cfaz2fFmXiKeFYAo
JUYwsS0zVpPwqFVJtH8nEHG17Szezqj1KWRYbIxHSoMOpU06ogFDT6EF/gHtR3N6
ggafd6De3KlKkHthbBARskdTuAK0TUV4MfaA+IRElDMxdCl2x9rHRSxKBVySYMwI
Hd0FYHX/AgMBAAECggEADhK8954ioO3UAPqse5el8PfYCQQSKO7HCtSyOOEV3LDl
7lHUvsQzCln32xl+j+s6JjFIndQTiiihUR/KVqHw3Bl8ZUvv8yNOLe2oiiBEoDP4
cTlFv4nQRrMWpUol9f+vPUAMtIOy3unvzuGt9HIjiwTHDXU9tTF2Cs2sXdbGeTpW
ELL2SG1FXMLH08a66eIundAXMbtu06N8Mb36oDfx2rE/F77lozUmvoNWZ9W9BUW3
6zK+VRG6MO5TqaBN4BhKQ8gxr9w/ovh6z9aKEgHtvhE8c1Jjnt19vG6yy1A/VI8j
hSjIFZUIi/PE6VZCqs05uE7bb0ut9+5+yWBYbCaj3QKBgQDbITMAwAjTProm7eYk
GzIKegckRddv5Q06FfujOIoEpjnauXNCS3UHbkusDxr1WWnYOIabyQ/aUMaVffY6
VB+vZat8bV8T8sN3c4Zqkyoq5M7V8Z64A3vxrUbIwArAqh48/lS78D0Y60ItXkVD
VIK/LQ/zQ3x6UklD4Ev9WdRXxQKBgQC/4UTS+Y+G0iW9ig+CsRO7/m98vZJGW0n5
Skvm7qUGGmhurfEnOsDB+i8Qf9wMNj3xW+P5GNpkeo969XU48sPElcAog6c6Dhz3
HLCHtrArpULX/qoZ7VphRgP/xePjhYvqTlBT33rt2HODcChys7NuF6+GSld/9RQO
pXRhtdju8wKBgQDVvWNXZvj0vGmtET37l/9Oksqmie1jOoOVVd32zm5prI4gF+Yi
EyIa1m2/bZh5GvcQLcq25/6rj0C0joH/URD67+u+WZx1A8W/nRLOn69w2XAa5SxR
Byz9hmvV4uRaG1WVXurdyq59wPPy9tIOo79IpLa7LOedFOhb6cuVWuqxlQKBgF/F
iXugUpIhe/Lh4SIDTm1L7sudN1BkqkSCX+YxAS9NqQhtS2ugOKvZOvqKRwPVYw+A
JQak8ASs48akk1DMYwhREmtmYuZoOu7gZAApID94qidzFeYBAVaCAub8F+XtN0vI
sPFcH1ht7CITriyqIwn1SofFvWzBn7Q7wx4uDMwfAoGAe4IanzZZgk2lIopbtUb5
LuhH+22O+LUU3iZmftgQpAmVcwYy4DP8Sa8IgsH3Xn6QGlKKVVl17FEcuGev50/c
SqZeazLX6Zf/JoDEGPX25SBgeTGj+vV7NvMi/qSFmW0CuW2uFb64F2vAyu4wsix5
KvSSF8+a+Xqp5EXGFQNsj+4=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIILDzCCCfegAwIBAgISA8X5/0JomSBgXTptip67SBc9MA0GCSqGSIb3DQEBCwUA
MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD
EwNSMTAwHhcNMjQwODI3MDgxMTQzWhcNMjQxMTI1MDgxMTQyWjAlMSMwIQYDVQQD
Expsb2NhbGhvc3QubG9jYWxzdGFjay5jbG91ZDCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKQ+mCTLVYyL0M66M+/eJwGEdNX+0p4BaX7tm4zQGRAyFYcL
PYxi04IhsvWNsfjVQ6YqY2MeCVs07TqzF1Zsy7CClj+cT19QRbcBjGygr88oH8ik
ngua4It4e3hGWpcbwE95JfpR5M/Tz/zJFOhplOAI2Os/fS6TcVJAMh/rCzEqFAwz
zwwRA5BeREZLQHsJ9rPZ8WZeIp4VgCglRjCxLTNWk/CoVUm0fycQcbXtLN7OqPUp
ZFhsjEdKgw6lTTqiAUNPoQX+Ae1Hc3qCBp93oN7cqUqQe2FsEBGyR1O4ArRNRXgx
9oD4hESUMzF0KXbH2sdFLEoFXJJgzAgd3QVgdf8CAwEAAaOCCCkwggglMA4GA1Ud
DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
AQH/BAIwADAdBgNVHQ4EFgQUjL+KDrAll1/D9srF4e6/GwekaA0wHwYDVR0jBBgw
FoAUu7zDR6XkvKnGw6RyDBCNojXhyOgwVwYIKwYBBQUHAQEESzBJMCIGCCsGAQUF
BzABhhZodHRwOi8vcjEwLm8ubGVuY3Iub3JnMCMGCCsGAQUFBzAChhdodHRwOi8v
cjEwLmkubGVuY3Iub3JnLzCCBi4GA1UdEQSCBiUwggYhgicqLmFtcGxpZnlhcHAu
bG9jYWxob3N0LmxvY2Fsc3RhY2suY2xvdWSCJyouY2xvdWRmcm9udC5sb2NhbGhv
c3QubG9jYWxzdGFjay5jbG91ZIIxKi5ka3IuZWNyLmV1LWNlbnRyYWwtMS5sb2Nh
bGhvc3QubG9jYWxzdGFjay5jbG91ZIIuKi5ka3IuZWNyLmV1LXdlc3QtMS5sb2Nh
bGhvc3QubG9jYWxzdGFjay5jbG91ZIIuKi5ka3IuZWNyLnVzLWVhc3QtMS5sb2Nh
bGhvc3QubG9jYWxzdGFjay5jbG91ZIIuKi5ka3IuZWNyLnVzLWVhc3QtMi5sb2Nh
bGhvc3QubG9jYWxzdGFjay5jbG91ZIIuKi5ka3IuZWNyLnVzLXdlc3QtMS5sb2Nh
bGhvc3QubG9jYWxzdGFjay5jbG91ZIIuKi5ka3IuZWNyLnVzLXdlc3QtMi5sb2Nh
bGhvc3QubG9jYWxzdGFjay5jbG91ZIIgKi5lbGIubG9jYWxob3N0LmxvY2Fsc3Rh
Y2suY2xvdWSCNCouZXUtY2VudHJhbC0xLm9wZW5zZWFyY2gubG9jYWxob3N0Lmxv
Y2Fsc3RhY2suY2xvdWSCMSouZXUtd2VzdC0xLm9wZW5zZWFyY2gubG9jYWxob3N0
LmxvY2Fsc3RhY2suY2xvdWSCKCouZXhlY3V0ZS1hcGkubG9jYWxob3N0LmxvY2Fs
c3RhY2suY2xvdWSCNCoubGFtYmRhLXVybC5ldS1jZW50cmFsLTEubG9jYWxob3N0
LmxvY2Fsc3RhY2suY2xvdWSCMSoubGFtYmRhLXVybC5ldS13ZXN0LTEubG9jYWxo
b3N0LmxvY2Fsc3RhY2suY2xvdWSCMSoubGFtYmRhLXVybC51cy1lYXN0LTEubG9j
YWxob3N0LmxvY2Fsc3RhY2suY2xvdWSCMSoubGFtYmRhLXVybC51cy1lYXN0LTIu
bG9jYWxob3N0LmxvY2Fsc3RhY2suY2xvdWSCMSoubGFtYmRhLXVybC51cy13ZXN0
LTEubG9jYWxob3N0LmxvY2Fsc3RhY2suY2xvdWSCMSoubGFtYmRhLXVybC51cy13
ZXN0LTIubG9jYWxob3N0LmxvY2Fsc3RhY2suY2xvdWSCHCoubG9jYWxob3N0Lmxv
Y2Fsc3RhY2suY2xvdWSCJyoub3BlbnNlYXJjaC5sb2NhbGhvc3QubG9jYWxzdGFj
ay5jbG91ZIInKi5zMy13ZWJzaXRlLmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNsb3Vk
gh8qLnMzLmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNsb3VkgiAqLnNjbS5sb2NhbGhv
c3QubG9jYWxzdGFjay5jbG91ZIImKi5zbm93Zmxha2UubG9jYWxob3N0LmxvY2Fs
c3RhY2suY2xvdWSCMSoudXMtZWFzdC0xLm9wZW5zZWFyY2gubG9jYWxob3N0Lmxv
Y2Fsc3RhY2suY2xvdWSCMSoudXMtZWFzdC0yLm9wZW5zZWFyY2gubG9jYWxob3N0
LmxvY2Fsc3RhY2suY2xvdWSCMSoudXMtd2VzdC0xLm9wZW5zZWFyY2gubG9jYWxo
b3N0LmxvY2Fsc3RhY2suY2xvdWSCMSoudXMtd2VzdC0yLm9wZW5zZWFyY2gubG9j
YWxob3N0LmxvY2Fsc3RhY2suY2xvdWSCGmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNs
b3VkgitzcXMuZXUtY2VudHJhbC0xLmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNsb3Vk
gihzcXMuZXUtd2VzdC0xLmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNsb3VkgihzcXMu
dXMtZWFzdC0xLmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNsb3VkgihzcXMudXMtZWFz
dC0yLmxvY2FsaG9zdC5sb2NhbHN0YWNrLmNsb3VkgihzcXMudXMtd2VzdC0xLmxv
Y2FsaG9zdC5sb2NhbHN0YWNrLmNsb3VkgihzcXMudXMtd2VzdC0yLmxvY2FsaG9z
dC5sb2NhbHN0YWNrLmNsb3VkMBMGA1UdIAQMMAowCAYGZ4EMAQIBMIIBBAYKKwYB
BAHWeQIEAgSB9QSB8gDwAHYASLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznY
hHMAAAGRkxmXAAAABAMARzBFAiAekzpZ4BDa1pqeUT7RmPK/m+MY8KMNabKFg/AW
lAdDBQIhAOXsXbLaXnUbLXDr4Sx5p6VXFMHJ8d4Iyleny0QzvZMWAHYAdv+IPwq2
+5VRwmHM9Ye6NLSkzbsp3GhCCp/mZ0xaOnQAAAGRkxmXUwAABAMARzBFAiAb8ttM
ztUxiVtgiF0R9WZ8Bmo7q75rLd+q+IOuVcSySwIhAJjmKMGXopkCr5HT3p1WT3MP
1thDnNBYWL+0G0wKK1/OMA0GCSqGSIb3DQEBCwUAA4IBAQCmo2uic9k6jUNJluPS
07aZVZZtI8a3yV1/swTNucYWg0YcF5Wbv5d2LH1QXeLThVrMRow4uI/GMkOmiQYb
WJC9i3YdUf1rlBsi+/oQuXxGOh4l23ZhCjB+Ntp7XP69Sdg0qmd0v6qP6vrdsCRJ
q5HD26LR5Gw55DgApomVpdQa9AYgoF2aeKZbJ9RG1M6Fu4LoC5d4hw3QfYGSJd85
qttWgU+2dAGb70FhQO1dGQZwlFCSWEn0RtOVXhstw6TspP3i9lqsLyhPvWxs0TDX
H1mKmInXK+uo7B0YT/n2oZ9TVjqyuHQ9t30VFS4Ixslr/n7UlLhUV2msflQgUAa3
uaDS
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL
YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a
/6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4
FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR
mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3
DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG
MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/
AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5
tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG
Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD
VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B
AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo
zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd
u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9
1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0
GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh
1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ
QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N
4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz
rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei
RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx
KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54=
-----END CERTIFICATE-----

0 comments on commit 8640bfd

Please sign in to comment.