From e140140c3fec4383327faa37e6e54cf8da52d6b1 Mon Sep 17 00:00:00 2001 From: viktorbarzin Date: Tue, 16 Feb 2021 00:01:14 +0000 Subject: [PATCH] Add LE renewal pipeline --- .drone.yml | 39 +++++++++ modules/kubernetes/bind/extra/viktorbarzin.me | 5 ++ modules/kubernetes/bind/main.tf | 2 +- modules/kubernetes/setup_tls_secret/main.tf | 17 ++-- modules/kubernetes/setup_tls_secret/renew.sh | 79 ++++++++++++++++++ secrets/fullchain.pem | Bin 0 -> 3478 bytes secrets/privkey.pem | Bin 0 -> 1726 bytes 7 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 modules/kubernetes/bind/extra/viktorbarzin.me create mode 100755 modules/kubernetes/setup_tls_secret/renew.sh create mode 100644 secrets/fullchain.pem create mode 100644 secrets/privkey.pem diff --git a/.drone.yml b/.drone.yml index 24e911fe..9a49e596 100644 --- a/.drone.yml +++ b/.drone.yml @@ -28,3 +28,42 @@ steps: - "git remote set-url origin git@github.com:ViktorBarzin/infra.git" - "git commit -m 'Drone CI deploy commit' || echo 'No changes'" - "GIT_SSH_COMMAND='ssh -i ./secrets/deploy_key -o IdentitiesOnly=yes' git push origin master" + +--- +kind: pipeline +type: kubernetes +name: renew-tls-certificate +trigger: + event: + - cron + cron: + - nightly + +steps: + - name: Prepare terraform files + image: alpine + commands: + - "apk update && apk add jq curl git git-crypt" + - | + curl -k https://kubernetes:6443/api/v1/namespaces/drone/configmaps/git-crypt-key -H "Authorization:Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" | jq -r .data.key | base64 -d > /tmp/key + - "git-crypt unlock /tmp/key" + - name: Run renew script + image: alpine + environment: + TF_VAR_prod: "true" + commands: + - "apk update && apk add git certbot expect curl gzip" + # Install terraform cli + - "curl https://releases.hashicorp.com/terraform/0.14.6/terraform_0.14.6_linux_amd64.zip | gzip -d > /usr/local/bin/terraform && chmod 775 /usr/local/bin/terraform" + - "terraform init" + - "./modules/kubernetes/setup_tls_secret/renew.sh" + - name: Commit updated certificates + image: alpine + commands: + - "apk update && apk add openssh-client git git-crypt" + - "mkdir ~/.ssh && ssh-keyscan -H github.com >> ~/.ssh/known_hosts" + - 'chmod 400 secrets/deploy_key' + - "git add ." + - "git remote set-url origin git@github.com:ViktorBarzin/infra.git" + - "git commit -m 'Drone CI Update TLS Certificates Commit' || echo 'No changes'" + - "GIT_SSH_COMMAND='ssh -i ./secrets/deploy_key -o IdentitiesOnly=yes' git push origin master" diff --git a/modules/kubernetes/bind/extra/viktorbarzin.me b/modules/kubernetes/bind/extra/viktorbarzin.me new file mode 100644 index 00000000..2acd3e4f --- /dev/null +++ b/modules/kubernetes/bind/extra/viktorbarzin.me @@ -0,0 +1,5 @@ +; additional bind records added via terraform automation +; entries are usually programmatically added to this file + +_acme-challenge IN TXT "6TiErEakwCp5Ryy3ICW8XVm_uGCUU9UhNZv4XFFnOkI" + diff --git a/modules/kubernetes/bind/main.tf b/modules/kubernetes/bind/main.tf index c8b75338..c11a7934 100644 --- a/modules/kubernetes/bind/main.tf +++ b/modules/kubernetes/bind/main.tf @@ -16,7 +16,7 @@ resource "kubernetes_config_map" "bind_configmap" { data = { "db.viktorbarzin.lan" = var.db_viktorbarzin_lan - "db.viktorbarzin.me" = var.db_viktorbarzin_me + "db.viktorbarzin.me" = format("%s%s", var.db_viktorbarzin_me, file("${path.module}/extra/viktorbarzin.me")) "named.conf" = var.named_conf "named.conf.local" = var.named_conf_local "named.conf.options" = var.named_conf_options diff --git a/modules/kubernetes/setup_tls_secret/main.tf b/modules/kubernetes/setup_tls_secret/main.tf index 3ad16d9e..a5d11383 100644 --- a/modules/kubernetes/setup_tls_secret/main.tf +++ b/modules/kubernetes/setup_tls_secret/main.tf @@ -1,7 +1,11 @@ -variable namespace {} -variable tls_secret_name {} -variable tls_crt {} -variable tls_key {} +variable "namespace" {} +variable "tls_secret_name" {} +variable "tls_crt" { + default = "" +} +variable "tls_key" { + default = "" +} resource "kubernetes_secret" "tls_secret" { metadata { @@ -9,8 +13,9 @@ resource "kubernetes_secret" "tls_secret" { namespace = var.namespace } data = { - "tls.crt" = var.tls_crt - "tls.key" = var.tls_key + # Cannot set default function in variable so use default behaviour here + "tls.crt" = var.tls_crt == "" ? file("${path.root}/secrets/fullchain.pem") : var.tls_crt + "tls.key" = var.tls_key == "" ? file("${path.root}/secrets/privkey.pem") : var.tls_key } type = "kubernetes.io/tls" } diff --git a/modules/kubernetes/setup_tls_secret/renew.sh b/modules/kubernetes/setup_tls_secret/renew.sh new file mode 100755 index 00000000..4ff4ae3e --- /dev/null +++ b/modules/kubernetes/setup_tls_secret/renew.sh @@ -0,0 +1,79 @@ +#!/usr/bin/expect -f + +set timeout -1 +set le_dir "/tmp/le/" +set config_dir "$le_dir/out/config" +set pwd [pwd] + +spawn certbot certonly --manual --preferred-challenge=dns --email me@viktorbarzin.me --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --manual-public-ip-logging-ok -d *.viktorbarzin.me -d viktorbarzin.me --config-dir $config_dir --work-dir $le_dir/workdir --logs-dir $le_dir/logsdir --no-eff-email + +set prompt "$" +set dns_file "$pwd/modules/kubernetes/bind/extra/viktorbarzin.me" +expect -re "Before continuing, verify" { + set challenge [ exec sh -c "echo '$expect_out(buffer)' | tail -n 3 | head -n 1" ] + set dns_record "_acme-challenge IN TXT \"$challenge\"" + puts $dns_record + puts $dns_file + + # Check if dns record is not already present + try { + set results [exec grep -q $dns_record $dns_file] + set status 0 + } trap CHILDSTATUS {results options} { + set status [lindex [dict get $options -errorcode] 2] + } + if {$status != 0} { + exec echo $dns_record | tee -a $dns_file + puts "Teed into file" + } else { + puts "DNS record '$dns_record' already in file" + } +} + +send -- "\r" +# Do the same for the 2nd dns record +expect -re "Before continuing, verify" { + set challenge [ exec sh -c "echo '$expect_out(buffer)' | tail -n 3 | head -n 1" ] + set dns_record "_acme-challenge IN TXT \"$challenge\"" + puts $dns_record + puts $dns_file + + # Check if dns record is not already present + try { + set results [exec grep -q $dns_record $dns_file] + set status 0 + } trap CHILDSTATUS {results options} { + set status [lindex [dict get $options -errorcode] 2] + } + if {$status != 0} { + exec echo $dns_record | tee -a $dns_file + puts "Teed into file" + } else { + puts "DNS record '$dns_record' already in file" + } +} + +# Force deployment recreation +exec terraform taint module.kubernetes_cluster.module.bind.module.bind-public-deployment.kubernetes_deployment.bind +# Apply changes to configmap and redeploy +exec >@stdout 2>@stderr terraform apply -auto-approve -target=module.kubernetes_cluster.module.bind + +# Wait for deployment update +# TODO: better to use k8s api. What we want is `kubectl rollout status deployment -l app=bind-public` as a curl +# exec bash -c 'while [[ $(kubectl get pods -l app=bind-public -o \'jsonpath={..status.conditions[\?(\@.type=="Ready")].status}\') != "True" ]]; do echo "waiting pod..." && sleep 1; done' +exec >@stdout echo 'Waiting for redeployment of bind...' +exec sleep 10 + +send -- "\r" + +# Clean up +exec sed -i "s/$dns_record//g" "$dns_file" + +# Success +expect ".*Congratulations!" + +# Copy cert and key to secrets dir +exec cp --remove-destination $config_dir/live/viktorbarzin.me/fullchain.pem ./secrets +exec cp --remove-destination $config_dir/live/viktorbarzin.me/privkey.pem ./secrets + +puts "Done renewing cert. Output certificates stored in ./secrets\n" diff --git a/secrets/fullchain.pem b/secrets/fullchain.pem new file mode 100644 index 0000000000000000000000000000000000000000..60d91fdb0eafce05ef975361e7ecf4fbbd71658a GIT binary patch literal 3478 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 E^Mvl$umAu6 literal 0 HcmV?d00001 diff --git a/secrets/privkey.pem b/secrets/privkey.pem new file mode 100644 index 0000000000000000000000000000000000000000..af948f757d1dd0ff731e6ed5ea76574d2484ca3d GIT binary patch literal 1726 zcmV;v20{4%M@dveQdv+`0J;xTb&Ut5pbzpYsS_wALk8rzFJ0PQ0X|7Js=}c&48>Q& z&Vq%qf0JH4*|-FsB>D|S4KqD(RUZm?p*6EZy*zGoVrhmyXx`38c1N z-Pe0FhX-Qq+{Ty~IJ+^p@kMw@momLB zHLS>X%OK7^j4AZ~;2~V~Z_~SeTSJ|P41bWcz}b1sf~xK$Im9(XIBM1(+={%t>POw> zNCZKC+`rO0Q#7Fr>mB=TQCv|0VW>hX>8HgiN* z+&bO#J6KrJ!t{*xCg`iW&%6E}$Q+2h$KhZj}qYsZiU?PH|`F;fO%vuF4Sx6`64Za8FljI&Z@0 zqzggx6&V>#70|G+_CU#;Ib%eEEOi9Bp9zwcuS24u$|4{HMIl3&s=cU=LJgYIGRrIv zyL>2qQ=CkM_nYkD3IsPE>*)aEVie}knAxKLqLbx|y7 z1p-}6QOxzfmxlg6~}UKH;lfkvlk zS(00OUtXJ|t9WLuI31c=VwAISpfI5q_`3ye0}es(M2zH*N!|BdmnR#(Qe`vmX*c$( zS7snsf^x4iq?;hgg`NF(UHJCi7c-J$_3Wfqf8ZUvrSp&}ganf@Qpq6o>T8eiQlVCS4Yl9{Czd> z`-)iF%rACZ$4T~ng`4on;}M?&Sbb8@YG1rTk0RQS$xiecprFU%zj7@B?yWTQC^en` zMKxJq^ay;OA^;GPmA#*|;ZOB6DNp4(4e*~aqyzt=a^iL`?@cT$RWF6urQQq6&`a6= zNjy4ZXjm7G4>9OL)pqMa)sC>%EY6=Hcu_4F4@cPvN{e$T zHKNVAJW!w9Rf;~6_uYfwjrnHrz;a@Dp)YiT_&Q`Vp%uoCAg?PV7kMYeR=NFs_D{)& z^fWuh!)*y5F!J3%yOWP^{(8r980SR_O?CW0dPX>|+Q;v8G$k|=cS*s?<_x|al}|S; zMop~Afo2P2UD6E1g9S$fCF39Bq@oG#!YbR-wlM{B$b=G1*A@F?qQe#*{N3xGvfhqG z07WmFd)%OY{x|JU0lIJ~_G<-7=UtvF)|yl_(<(A8A?uq?uHoC)d(d!NQR5`vamoHohrV;th_DhF4#6>yA4obI$j?>eU6z zY)Ih#JPWpv;`UqcyB}hpZnXPn0Cxp_p4(Jrk;dfXWs=mnY1Nw|SadU#eBizfc1q|~b& z4LxR+I?nctez+bP4Z#{DaL}n>x^7FZ>x^O3F}*dk2Y2^BCy;@5G!!!g+UILm%&Nh4 zq2FEmm56l1Wib?jFS=~ZluMA75ixu9E)4W!$zb0l0jhz=IBn|~WiljsK*5&Toz9Xv zDFx~*9(^AMv*XKABo9x5CnAR6XVR5LweY9VW1(Nq_1f3TH)gQ!oLI@g=JMR*TATJo zrW-uFZ$~&6l058cv!xbG@Sf<~wN5sVyx>~B-ZIo6Yi4jlOJoHrSnzSfN$+*n22?(} zWTt)KF@3k#Q_l)vpTtQw4Qk48c0P_R2pA*0^{1t?B)P?IC=b;TLxe#qk^BBu=dzyh zih20W(zdQ6`X*Jy@RqgkU_=x0;<4fimz!JKvyB+ffVFd+Jg}@pz;mMefXzSQA^~X4 zei_G5G-juByg>JhsSf*kKw>%$|25$C)Mg$#$t2_tV8llNCQYNlXF-Lpb2JdMP1kI7 za4@R;p24U|DImgG+-q^I=3baKZa`?QDm*|X9s*#S{br{>Kk2la;CTl#4v;1&a!*p# z@BE}f<=s}OYC64OqK;U+m|M!iH%s>BjZsrx?E& UE_Mlq