From 5c81757a4cc23e5bfe3a2458a91bdbc5794bcd79 Mon Sep 17 00:00:00 2001 From: jaime Bernabe <6184069+Monitob@users.noreply.github.com> Date: Tue, 21 Dec 2021 15:45:21 +0100 Subject: [PATCH] fix(lb): handle support for valid custom certificates (#971) * fix(k8s): cassette * feat(lb): create-certificate script to wrap the ACME client on letsencrypt and scaleway provider * feat(lb): add wait to certificate creation * feat(lb): remove custom test on lb * feat(lb): remove .lego directory * feat(lb): remove custom certificate cassette * feat(lb): add new certificate test * feat(lb): update cassette --- .gitignore | 3 + scaleway/resource_lb_certificate.go | 92 +- scaleway/resource_lb_certificate_test.go | 109 +- .../lb-certificate-basic.cassette.yaml | 1500 +++++++++++++---- scripts/create-certificate.sh | 151 ++ 5 files changed, 1532 insertions(+), 323 deletions(-) create mode 100755 scripts/create-certificate.sh diff --git a/.gitignore b/.gitignore index 1baa689849..5623a1c6bc 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ website/vendor dist/ terraform-provider-scaleway + +# Lego ACME client +.lego/ diff --git a/scaleway/resource_lb_certificate.go b/scaleway/resource_lb_certificate.go index d03d64e8d4..64bf8be08e 100644 --- a/scaleway/resource_lb_certificate.go +++ b/scaleway/resource_lb_certificate.go @@ -140,11 +140,33 @@ func resourceScalewayLbCertificateCreate(ctx context.Context, d *schema.Resource return diag.FromErr(errors.New("you need to define either letsencrypt or custom_certificate configuration")) } + retryInterval := DefaultWaitLBRetryInterval + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: lbID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + // check err waiting process + if err != nil { + return diag.FromErr(err) + } + res, err := lbAPI.CreateCertificate(createReq, scw.WithContext(ctx)) if err != nil { return diag.FromErr(err) } + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: lbID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + d.SetId(newZonedIDString(zone, res.ID)) return resourceScalewayLbCertificateRead(ctx, d, meta) @@ -169,6 +191,17 @@ func resourceScalewayLbCertificateRead(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } + retryInterval := DefaultWaitLBRetryInterval + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: res.LB.ID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + _ = d.Set("lb_id", newZonedIDString(zone, res.LB.ID)) _ = d.Set("name", res.Name) _ = d.Set("common_name", res.CommonName) @@ -186,6 +219,25 @@ func resourceScalewayLbCertificateUpdate(ctx context.Context, d *schema.Resource return diag.FromErr(err) } + cert, err := lbAPI.GetCertificate(&lb.ZonedAPIGetCertificateRequest{ + CertificateID: ID, + Zone: zone, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + retryInterval := DefaultWaitLBRetryInterval + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: cert.LB.ID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + req := &lb.ZonedAPIUpdateCertificateRequest{ CertificateID: ID, Zone: zone, @@ -197,6 +249,16 @@ func resourceScalewayLbCertificateUpdate(ctx context.Context, d *schema.Resource return diag.FromErr(err) } + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: cert.LB.ID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + return resourceScalewayLbCertificateRead(ctx, d, meta) } @@ -206,14 +268,42 @@ func resourceScalewayLbCertificateDelete(ctx context.Context, d *schema.Resource return diag.FromErr(err) } + cert, err := lbAPI.GetCertificate(&lb.ZonedAPIGetCertificateRequest{ + CertificateID: ID, + Zone: zone, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + retryInterval := DefaultWaitLBRetryInterval + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: cert.LB.ID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + err = lbAPI.DeleteCertificate(&lb.ZonedAPIDeleteCertificateRequest{ Zone: zone, CertificateID: ID, }, scw.WithContext(ctx)) - if err != nil && !is404Error(err) { return diag.FromErr(err) } + _, err = lbAPI.WaitForLb(&lb.ZonedAPIWaitForLBRequest{ + Zone: zone, + LBID: cert.LB.ID, + Timeout: scw.TimeDurationPtr(defaultInstanceServerWaitTimeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + return nil } diff --git a/scaleway/resource_lb_certificate_test.go b/scaleway/resource_lb_certificate_test.go index da9f28b464..9ac9e83a44 100644 --- a/scaleway/resource_lb_certificate_test.go +++ b/scaleway/resource_lb_certificate_test.go @@ -114,26 +114,97 @@ func TestAccScalewayLbCertificate_Basic(t *testing.T) { custom_certificate { certificate_chain = < Generating certificate..." + +if ! which lego > /dev/null; then + echo "==> Installing lego..." + go install github.com/go-acme/lego/v4/cmd/lego@latest +fi + +############################################################################## +# functions +############################################################################## + +usage() +{ + cat << EOF + +Usage: create-certificate [options...] [ ... ] +Options: + -e, --email EMAIL Your email from your scaleway account + -h, --help This help + -t, --test Use staging API of Let's Encrypt for testing the script + -d, --debug Debug mode, print additional debug output + -a, --action The action to execute [run, renew, list] + + +The first domain parameter should be your main domain name with the subdomains following after it. + +Example: $0 -e me@example.com example.com www.example.com + +EOF +} + +# general log messages +log() +{ + echo "#### ${1}" +} + +# error messages +error() +{ + echo "ERROR: ${1}" >&2 +} + +# debug messages +debug() +{ + if [ "${VERBOSE}" = "true" ]; + then + # do not output to stdout, else debug output from api_request would + # become part of the function response + echo "${1}" >&2 + fi +} + +# last command +on_exit() +{ + debug "EXIT ${?}" + exit +} + +############################################################################## +# main +############################################################################## + + +# stop on error +set -e +trap on_exit EXIT + +# defaults +# ACME API to use +API="https://acme-v02.api.letsencrypt.org/directory" +API_STAGING="https://acme-staging-v02.api.letsencrypt.org/directory" +ACTION="run" +CONTACT_EMAIL="hashicorp@scaleway.com" +DOMAINS=() +VERBOSE="false" + +# arg handling +if [ ${#} -lt 1 ]; +then + error "Missing parameter" + usage + exit 1 +fi + +while [ ${#} -gt 0 ]; +do + ARG="${1}" + case "${ARG}" in + -e|--email) + shift + CONTACT_EMAIL="${1}" + ;; + -h|--help) + usage + exit + ;; + -t|--test) + # use staging API for testing + log "Using staging API" + API="${API_STAGING}" + ;; + -a|--action) + shift + ACTION_LEGO="${1}" + ;; + -d|--debug) + export TF_LOG="DEBUG" + export SCW_DEBUG=1 + ;; + *) + X="${ARG/-*/}" + if [ -z "${X}" ]; + then + error "Unknown option" + usage + exit 1 + else + DOMAINS[${#DOMAINS[@]}]="${ARG}" + fi + esac + # shift the option flag, option flag values (if any) are shifted in case block + shift +done + +if [ ${#DOMAINS[@]} -eq 0 ]; +then + error "Domain missing" + usage + exit 1 +fi + +DOMAIN="${DOMAINS[0]}" + +api_request() +{ + MAIL="${1}" + DOMAINS_ARRAY="${2}" + ACTION_ARG="${3}" + LEGO_OUT="$(SCALEWAY_API_TOKEN=${SCW_SECRET_KEY} lego --server ${API} --accept-tos --email ${MAIL} --pem --dns scaleway --domains ${DOMAINS_ARRAY} ${ACTION_ARG})" + echo "${LEGO_OUT}" + return 0 +} + +api_request ${CONTACT_EMAIL} ${DOMAINS} ${ACTION_LEGO} + +log "Finished." \ No newline at end of file