Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add DNS alias mode support via dnschallengealias parameter #4

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/beta-builder.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Beta Builder

env:
BUILD_ARGS: "--test"

on:
push:
branches:
- main
paths:
- 'acme-sh_beta/**'
- '!acme-sh_beta/CHANGELOG.md'

pull_request:
branches:
- main
paths:
- 'acme-sh_beta/**'
- '!acme-sh_beta/CHANGELOG.md'

jobs:

build:

runs-on: ubuntu-latest
name: Build acme.sh beta addon for ${{ matrix.arch }}
strategy:
matrix:
arch: ["aarch64", "amd64", "armhf", "armv7", "i386"]
permissions:
contents: read
packages: write

steps:
- name: Check out repository
uses: actions/[email protected]

- name: Get information
id: info
uses: home-assistant/actions/helpers/info@master
with:
path: "./acme-sh_beta"

- name: Check if add-on should be built
id: check
run: |
if [[ "${{ steps.info.outputs.image }}" == "null" ]]; then
echo "Image property is not defined, skipping build"
echo "build_arch=false" >> $GITHUB_OUTPUT;
elif [[ "${{ steps.info.outputs.architectures }}" =~ ${{ matrix.arch }} ]]; then
echo "build_arch=true" >> $GITHUB_OUTPUT;
echo "image=$(echo ${{ steps.info.outputs.image }} | cut -d'/' -f3)" >> $GITHUB_OUTPUT;
if [[ -z "${{ github.head_ref }}" ]] && [[ "${{ github.event_name }}" == "push" ]]; then
echo "BUILD_ARGS=" >> $GITHUB_ENV;
fi
else
echo "${{ matrix.arch }} is not a valid arch, skipping build";
echo "build_arch=false" >> $GITHUB_OUTPUT;
fi

- name: Login to GitHub Container Registry
if: env.BUILD_ARGS != '--test'
uses: docker/[email protected]
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build add-on
if: steps.check.outputs.build_arch == 'true'
uses: home-assistant/[email protected]
with:
args: |
${{ env.BUILD_ARGS }} \
--${{ matrix.arch }} \
--target /data/acme-sh_beta \
--image "${{ steps.check.outputs.image }}" \
--docker-hub "ghcr.io/${{ github.repository_owner }}" \
--addon
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

This Home Assistant addon uses `acme.sh` to obtain SSL/TLS certificates from ZeroSSL or Let's Encrypt.

## Currently in beta testing

[DNS alias mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode) support via the `dnschallengealias`
configuration parameter.

## Configuration

Tested with the *dns_oci* configuration but It should work, the `dnsEnvVariables` can be configured with any environment required for `acme.sh` to work.
Tested with the *dns_oci* configuration but It should work, the `dnsEnvVariables` can be configured with any environment
variable required for `acme.sh` to work.


```yaml
accountemail: [email protected]
acmeprovider: zerossl
domains:
- home.example.com
dnsprovider: dns_oci
dnschallengealias:
dnsenvvars:
- name: OCI_CLI_USER
value: xxxx
Expand Down
27 changes: 27 additions & 0 deletions acme-sh_beta/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Changelog

## 2024.8.1 (beta)

### New features

- Added support for [DNS alias mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode)
via the `dnschallengealias` configuration field. The content of this field (if configured) is passed
to the `--challenge-alias` command-line parameter of `acme.sh`.

## 2024.5.1

### BREAKING CHANGE

- The `domain` configuration field has been replaced by the `domains` list which requires
at least one domain to be configured. Multiple domain names are also supported, but all
domain names must be managed by the same DNS provider configuration.

### New features

- supports wildcard certificates
- automatically restarts NGINX Home Assistant SSL Proxy (if enabled)

### Other fixes

- migrate from JSON to YAML configuration
- pre-built images available from GitHub Container Registry
26 changes: 26 additions & 0 deletions acme-sh_beta/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ARG BUILD_FROM
FROM $BUILD_FROM

ENV LE_CONFIG_HOME /data/acme.sh
ENV AUTO_UPGRADE 1

RUN apk --no-cache add -f \
openssl \
openssh-client \
coreutils \
bind-tools \
curl \
sed \
socat \
tzdata \
oath-toolkit-oathtool \
tar \
libidn \
jq

#Install
RUN curl https://get.acme.sh | sh && \
ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - && \
cp "$LE_CONFIG_HOME/account.conf" /default_account.conf

COPY rootfs/ /
11 changes: 11 additions & 0 deletions acme-sh_beta/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
build_from:
aarch64: "ghcr.io/home-assistant/aarch64-base:3.15"
amd64: "ghcr.io/home-assistant/amd64-base:3.15"
armhf: "ghcr.io/home-assistant/armhf-base:3.15"
armv7: "ghcr.io/home-assistant/armv7-base:3.15"
i386: "ghcr.io/home-assistant/i386-base:3.15"
labels:
org.opencontainers.image.title: "acme.sh addon (beta)"
org.opencontainers.image.description: "This addon uses acme.sh and its DNS provider plugins to issue and renew SSL certificates."
org.opencontainers.image.source: "https://github.com/Djelibeybi/homeassistant-acme.sh-addon"
org.opencontainers.image.licenses: "GPL-3.0"
43 changes: 43 additions & 0 deletions acme-sh_beta/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: acme.sh addon (beta)
version: "2024.8.1"
slug: acme-sh_beta
image: "ghcr.io/djelibeybi/homeassistant-acme.sh-addon_beta-{arch}"
description: >-
This addon uses acme.sh and its DNS provider plugins to issue and renew SSL certificates.
url: https://github.com/Djelibeybi/homeassistant-acme.sh-addon
arch:
- armhf
- armv7
- aarch64
- amd64
- i386
map:
- ssl:rw
hassio_api: true
hassio_role: manager
init: false
options:
accountemail: null
acmeprovider: zerossl
domains: null
dnsprovider: null
dnschallengealias:
dnsenvvars:
- name: null
value: null
keylength: "4096"
fullchainfile: fullchain.pem
keyfile: privkey.pem
schema:
accountemail: str
acmeprovider: list(letsencrypt|letsencrypt_test|buypass|buypass_test|zerossl|sslcom|google|googletest)
domains:
- str
dnsprovider: str
dnschallengealias: str?
dnsenvvars:
- name: str
value: str
keylength: list(2048|4096|ec-256|ec-384|ec-512)
fullchainfile: str
keyfile: str
99 changes: 99 additions & 0 deletions acme-sh_beta/rootfs/etc/cont-init.d/issue-cert.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
CONFIG_PATH=/data/options.json
LE_CONFIG_HOME="/data/acme.sh"
RESTART_SCRIPT="/usr/local/bin/restart-nginx.sh"

[ ! -d "$LE_CONFIG_HOME" ] && mkdir -p "$LE_CONFIG_HOME"

if [ ! -f "$LE_CONFIG_HOME/account.conf" ]; then
bashio::log.info "Copying the default account.conf file"
cp /default_account.conf "$LE_CONFIG_HOME/account.conf"
fi

if [ ! -f "$RESTART_SCRIPT" ]; then
bashio::log.error "Restart script not found. Please upgrade or reinstall this addon."
fi

if [ ! -x "$RESTART_SCRIPT" ]; then
bashio::log.info "Marking restart script executable."
chmod +x "$RESTART_SCRIPT"
fi

if bashio::config.is_empty 'domains'; then
bashio::log.fatal
bashio::log.fatal 'Configuration of this addon is incomplete.'
bashio::log.fatal
bashio::log.fatal 'At least one domain must be specified using the "domains" option.'
bashio::log.fatal
bashio::exit.nok
else
DOMAINS=()
while read -r DOMAIN; do
DOMAINS+=( "$DOMAIN" )
done <<< "$(bashio::config 'domains')"
fi

ACCOUNT_EMAIL=$(bashio::config 'accountemail')
DNS_PROVIDER=$(bashio::config 'dnsprovider')
ACME_PROVIDER=$(bashio::config 'acmeprovider')
DNS_ENV_VARS=$(jq --raw-output '.dnsenvvars | map("export \(.name)='\''\(.value)'\''") | .[]' $CONFIG_PATH)
KEY_LENGTH=$(bashio::config 'keylength')
FULLCHAIN_FILE=$(bashio::config 'fullchainfile')
KEY_FILE=$(bashio::config 'keyfile')

DNS_CHALLENGE_ALIAS_PARAM=""

if bashio::config.has_value 'dnschallengealias'; then
DNS_CHALLENGE_ALIAS=$(bashio::config 'dnschallengealias')
DNS_CHALLENGE_ALIAS_PARAM=$(printf " --challenge-alias %s" "$DNS_CHALLENGE_ALIAS")
fi

# shellcheck source=/dev/null
source <(echo "$DNS_ENV_VARS");

if [ ! -f "/$LE_CONFIG_HOME/.registered" ]; then
bashio::log.info "Registering account"
acme.sh --register-account --server "$ACME_PROVIDER" -m "$ACCOUNT_EMAIL"
touch /$LE_CONFIG_HOME/.registered
fi

if [ ! -f "/$LE_CONFIG_HOME/.set-default" ]; then
bashio::log.info "Setting default CA"
acme.sh --set-default-ca --server "$ACME_PROVIDER"
touch "/$LE_CONFIG_HOME/.set-default"
fi

function issue {
# Issue the certificate, if necessary. Exit cleanly if it exists.
bashio::log.info "Issuing certificates for ${DOMAINS[@]}"

local RENEW_SKIP=2
local DOMAIN_PARAMS=$(printf " -d %s" "${DOMAINS[@]}")

acme.sh --issue ${DOMAIN_PARAMS} \
--keylength "$KEY_LENGTH" \
--dns "$DNS_PROVIDER" \
${DNS_CHALLENGE_ALIAS_PARAM}
|| { ret=$?; [ $ret -eq ${RENEW_SKIP} ] && return 0 || return $ret ;}
}

issue

function install {
# Install the certificate and restart NGINX, if necessary
bashio::log.info "Installing private key to /ssl/$KEY_FILE and certificate to /ssl/$FULLCHAIN_FILE"

ECC_ARG=$( [[ ${KEY_LENGTH} == ec-* ]] && echo '--ecc' || echo '' )

# shellcheck disable=SC2086
acme.sh --install-cert --domain "${DOMAINS[0]}" $ECC_ARG \
--key-file "/ssl/$KEY_FILE" \
--fullchain-file "/ssl/$FULLCHAIN_FILE" \
--reloadcmd "$RESTART_SCRIPT"

}

install

bashio::log.info "SSL certificate successfully issued and installed."
17 changes: 17 additions & 0 deletions acme-sh_beta/rootfs/etc/services.d/crond/finish
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bashio
# shellcheck shell=bash

# ==============================================================================
# Take down the S6 supervision tree when crond fails
# s6-overlay docs: https://github.com/just-containers/s6-overlay
# ==============================================================================

declare APP_EXIT_CODE=${1}

if [[ "${APP_EXIT_CODE}" -ne 0 ]] && [[ "${APP_EXIT_CODE}" -ne 256 ]]; then
bashio::log.warning "Halt add-on with exit code ${APP_EXIT_CODE}"
echo "${APP_EXIT_CODE}" > /run/s6-linux-init-container-results/exitcode
exec /run/s6/basedir/bin/halt
fi

bashio::log.info "Service restart after closing"
6 changes: 6 additions & 0 deletions acme-sh_beta/rootfs/etc/services.d/crond/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash

# Run crond
bashio::log.info "Starting crond..."
exec crond -f -L /dev/stdout
15 changes: 15 additions & 0 deletions acme-sh_beta/rootfs/usr/local/bin/restart-nginx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash

# check that the core NGINX proxy addon is installed
if bashio::addons.installed 'core_nginx_proxy'; then

# check that NGINX is actually running
if [ "$( bashio::addon.state 'core_nginx_proxy' )" == "started" ]; then

# tell the Supervisor to restart the NGINX addon
bashio::log.info 'Restarting NGINX Home Assistant SSL Proxy'
bashio::addon.restart 'core_nginx_proxy'
fi

fi