Skip to content

Commit

Permalink
Add contrib directory (#45)
Browse files Browse the repository at this point in the history
The new contrib directory contains a script that generates an EC key-pair that satisfies golang >=1.15 CommonName deprecation. 

Co-authored-by: J.C. Jones <[email protected]>
Co-authored-by: Samantha <[email protected]>
  • Loading branch information
3 people authored Feb 22, 2023
1 parent cb8f755 commit 1d05a27
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 0 deletions.
45 changes: 45 additions & 0 deletions contrib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Contrib
This collection of scripts and files helps us further configure our unbounds and unbound_exporters.

## unbound-control-setup.sh

From [Golang 1.15 docs:](https://golang.google.cn/doc/go1.15#commonname)
> X.509 CommonName deprecation
> The deprecated, legacy behavior of treating the CommonName field on X.509 certificates as a host name when no Subject Alternative Names are present is now disabled by default. It can be temporarily re-enabled by adding the value x509ignoreCN=0 to the GODEBUG environment variable.
> Note that if the CommonName is an invalid host name, it's always ignored, regardless of GODEBUG settings. Invalid names include those with any characters other than letters, digits, hyphens and underscores, and those with empty labels or trailing dots.
Unbound still ships with an `unbound-control-setup` that generates a problematic keypair. This script will generate a keypair that satisfies newer versions of Golang.

Generate the new keypair
```
$ bash unbound-control-setup.sh
```

You'll then want to configure `/etc/unbound/unbound.conf` with the following stanza

```
$ cat /etc/unbound/unbound.conf
...
remote-control:
control-enable: yes
control-use-cert: yes
server-key-file: "/etc/unbound/unbound_server_ec.key"
server-cert-file: "/etc/unbound/unbound_server_ec.pem"
control-key-file: "/etc/unbound/unbound_control_ec.key"
control-cert-file: "/etc/unbound/unbound_control_ec.pem"
```

Test that you can still communicate with unbound via `unbound_control`. You should be able to see metrics.
```
$ unbound-control stats_noreset
thread0.num.queries=35
thread0.num.queries_ip_ratelimited=0
thread0.num.cachehits=25
thread0.num.cachemiss=10
thread0.num.prefetch=0
thread0.num.expired=0
...
```

To reconfigure `unbound_exporter` as a systemd service, see [this file](unbound_exporter.service).
147 changes: 147 additions & 0 deletions contrib/unbound-cert-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/env bash

# Generally based on /usr/sbin/unbound-control-setup but adapted to catch
# up to ~2010. You know, x509v3, secp384r1, AKIs, stuff like that.

# directory for files
DESTDIR="${UNBOUND_CONFIG_DIR:-/etc/unbound}"

# validity period for certificates
DAYS="${UNBOUND_CERT_LIFETIME:-397}"

# hash algorithm
HASH=sha256

# base name for unbound CA keys
CA_BASE=unbound_ca_ec

# base name for unbound server keys
SVR_BASE=unbound_server_ec

# base name for unbound-control keys
CTL_BASE=unbound_control_ec

# we want -rw-r----- access (say you run this as root: grp=yes (server), all=no).
umask 0027

# end of options

# functions:
error ( ) {
echo "$0 fatal error: ${1}"
exit 1
}

# go!:
echo "setup in directory ${DESTDIR}"
cd "${DESTDIR}" || error "could not cd to ${DESTDIR}"

# create certificate keys; do not recreate if they already exist.
if test -f "${CA_BASE}.key"; then
echo "${CA_BASE}.key exists"
else
echo "generating ${CA_BASE}.key"
openssl ecparam -genkey -name secp384r1 > ${CA_BASE}.key || error "could not gen ecdsa"
fi
if test -f "${SVR_BASE}.key"; then
echo "${SVR_BASE}.key exists"
else
echo "generating ${SVR_BASE}.key"
openssl ecparam -genkey -name secp384r1 > ${SVR_BASE}.key || error "could not gen ecdsa"
fi
if test -f "${CTL_BASE}.key"; then
echo "${CTL_BASE}.key exists"
else
echo "generating ${CTL_BASE}.key"
openssl ecparam -genkey -name secp384r1 > ${CTL_BASE}.key || error "could not gen ecdsa"
fi

# create self-signed cert CSR for server
cat > ca_request.cfg <<EOCAConfig
[req]
prompt = no
distinguished_name = req_distinguished_name
x509_extensions = req_v3_extensions
[req_distinguished_name]
commonName = unbound-ca
[req_v3_extensions]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
EOCAConfig
test -f ca_request.cfg || error "could not create ca_request.cfg"

echo "creating ${CA_BASE}.pem (self signed certificate)"
openssl req -key "${CA_BASE}.key" -config ca_request.cfg -new -x509 -days "${DAYS}" -out "${CA_BASE}.pem" || error "could not create ${CA_BASE}.pem"

# --------------

# create server cert CSR and sign it, piped
cat > server_request.cfg <<EOServerConfig
[req]
prompt = no
distinguished_name = req_distinguished_name
[req_distinguished_name]
commonName = unbound
EOServerConfig
test -f server_request.cfg || error "could not create server_request.cfg"

cat > server_exts.cfg <<EOServerConfig
subjectAltName = @alt_names
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
extendedKeyUsage = serverAuth
[alt_names]
DNS.1 = $(hostname)
DNS.2 = unbound
DNS.3 = localhost
EOServerConfig
test -f server_exts.cfg || error "could not create server_exts.cfg"

echo "create ${SVR_BASE}.pem (signed server certificate)"
openssl req -key "${SVR_BASE}.key" -config server_request.cfg -new | openssl x509 -req -days "${DAYS}" -CA "${CA_BASE}.pem" -CAkey "${CA_BASE}.key" -CAcreateserial -"${HASH}" -extfile server_exts.cfg -out "${SVR_BASE}.pem"
test -f ${SVR_BASE}.pem || error "could not create ${SVR_BASE}.pem"

# --------------

# create client cert CSR and sign it, piped
cat > client_request.cfg <<EOCertConfig
[req]
prompt = no
distinguished_name = req_distinguished_name
[req_distinguished_name]
commonName = unbound-control
EOCertConfig
test -f client_request.cfg || error "could not create client_request.cfg"

cat > client_exts.cfg <<EOCertConfig
extendedKeyUsage = clientAuth
EOCertConfig
test -f client_exts.cfg || error "could not create client_exts.cfg"

echo "create ${CTL_BASE}.pem (signed client certificate)"
openssl req -key "${CTL_BASE}.key" -config client_request.cfg -new | openssl x509 -req -days "${DAYS}" -CA "${CA_BASE}.pem" -CAkey "${CA_BASE}.key" -CAcreateserial -"${HASH}" -extfile client_exts.cfg -out "${CTL_BASE}.pem"
test -f "${CTL_BASE}.pem" || error "could not create ${CTL_BASE}.pem"

# --------------

# set desired permissions
chmod 0640 "${CA_BASE}.key" "${SVR_BASE}.key" "${CTL_BASE}.key"
chmod 0644 "${CA_BASE}.pem" "${SVR_BASE}.pem" "${CTL_BASE}.pem"

# cleanup
rm -f ca_request.cfg client_request.cfg client_exts.cfg server_request.cfg server_exts.cfg *.srl

openssl x509 -text -in "${CA_BASE}.pem"
openssl x509 -text -in "${SVR_BASE}.pem"
openssl x509 -text -in "${CTL_BASE}.pem"

echo "Satisfy unbound daemon/remote.c SSL_CTX_use_certificate_chain_file by appending ${CA_BASE}.pem to ${SVR_BASE}.pem"
cat "${CA_BASE}.pem" >> "${SVR_BASE}.pem"

echo "Setup success. Certificates created."
15 changes: 15 additions & 0 deletions contrib/unbound_exporter.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=Prometheus exporter for Unbound metrics, written in Go with pluggable metric collectors. The metrics exporter converts Unbound metric names to Prometheus metric names and labels by using a set of regular expressions.
Documentation=https://github.com/letsencrypt/unbound_exporter
After=network.target

[Service]
Type=simple
ExecStart=/bin/unbound_exporter \
-unbound.ca "/etc/unbound/unbound_ca_ec.pem" \
-unbound.cert "/etc/unbound/unbound_control_ec.pem" \
-unbound.key "/etc/unbound/unbound_control_ec.key" \
-unbound.host "tcp://localhost:8953"

[Install]
WantedBy=multi-user.target

0 comments on commit 1d05a27

Please sign in to comment.