From 628f37fa374d6af30803701eaa804f3bc98ca34f Mon Sep 17 00:00:00 2001 From: Trammell Hudson Date: Tue, 3 May 2022 17:11:57 +0000 Subject: [PATCH] nginx renewal fixes, oauth mastodon setup, secret restructure, etc --- env.production | 1 + hedgedoc/setup | 30 +++++++++------ keycloak/client-delete | 38 +++++++++++++++++++ keycloak/docker-compose.yaml | 6 ++- keycloak/env.production | 1 - keycloak/setup | 1 + mastodon/docker-compose.yaml | 4 +- mastodon/env.production | 6 +-- mastodon/setup | 47 +++++++++++------------ nextcloud/docker-compose.yaml | 7 ++-- nextcloud/env.production | 2 +- nextcloud/setup | 71 ++++++++++++++++++----------------- nginx/certbot-renew | 21 +++++++---- nginx/setup | 43 +++++++++++++-------- 14 files changed, 173 insertions(+), 105 deletions(-) create mode 100755 keycloak/client-delete diff --git a/env.production b/env.production index 8e6cab5..64adb12 100644 --- a/env.production +++ b/env.production @@ -5,3 +5,4 @@ KEYCLOAK_HOSTNAME=login.hackerspace.zone HEDGEDOC_HOSTNAME=docs.hackerspace.zone MASTODON_HOSTNAME=social.hackerspace.zone NEXTCLOUD_HOSTNAME=cloud.hackerspace.zone +GRAFANA_HOSTNAME=dashboard.hackerspace.zone diff --git a/hedgedoc/setup b/hedgedoc/setup index df89542..0d3e742 100755 --- a/hedgedoc/setup +++ b/hedgedoc/setup @@ -3,20 +3,24 @@ die() { echo >&2 "$@" ; exit 1 ; } DIRNAME="$(dirname $0)" cd "$DIRNAME" -[ -r env.production ] && source env.production -[ -r ../env.production ] && source ../env.production +source ../env.production || die "no top levle env?" +source env.production || die "no local env?" -cd ../keycloak +docker-compose down -source env.production +# regenerate the client secrets +CLIENT_SECRET="$(openssl rand -hex 20)" +SESSION_SECRET="$(openssl rand -hex 20)" -sudo docker-compose exec -T keycloak \ - /opt/keycloak/bin/kcadm.sh \ - create clients \ - --user admin \ - --password "$KEYCLOAK_ADMIN_PASSWORD" \ - -r "$REALM" \ - -f - < env.secrets +CMD_OAUTH2_CLIENT_SECRET=$CLIENT_SECRET +CMD_SESSION_SECRET=$SESSION_SECRET +EOF + +../keycloak/client-delete hedgedoc + +../keycloak/client-create <&2 "$@" ; exit 1 ; } + +DIRNAME="$(dirname $0)" +cd "$DIRNAME" + +source ../env.production || die "no top levle env?" +source env.production || die "no local env?" +source env.secrets || die "no local secrets?" + +# try to get the clients by name +CLIENT_NAME="$1" +if [ -z "$CLIENT_NAME" ]; then + die "usage: $0 clientName" +fi + +CLIENT_ID="$(docker-compose exec -T keycloak \ + /opt/keycloak/bin/kcadm.sh \ + get clients \ + --server http://localhost:8080/ \ + --user admin \ + --password "$KEYCLOAK_ADMIN_PASSWORD" \ + -r "$REALM" \ +| jq -r ".[] | select( .clientId == \"$CLIENT_NAME\" ).id")" + +if [ -z "$CLIENT_ID" ]; then + die "$CLIENT_NAME: no such client" +fi + +echo "$0: $CLIENT_NAME = $CLIENT_ID" +docker-compose exec -T keycloak \ + /opt/keycloak/bin/kcadm.sh \ + delete "clients/$CLIENT_ID" \ + --server http://localhost:8080/ \ + --user admin \ + --password "$KEYCLOAK_ADMIN_PASSWORD" \ + -r "$REALM" \ + || die "$CLIENT_NAME($CLIENT_ID): unable to remove" diff --git a/keycloak/docker-compose.yaml b/keycloak/docker-compose.yaml index 1730956..a3d4f96 100644 --- a/keycloak/docker-compose.yaml +++ b/keycloak/docker-compose.yaml @@ -17,10 +17,12 @@ services: keycloak: image: quay.io/keycloak/keycloak:18.0.0 - entrypoint: /opt/keycloak/bin/kc.sh start-dev --proxy=edge + entrypoint: /opt/keycloak/bin/kc.sh start --hostname="$${KEYCLOAK_HOSTNAME}" --proxy=edge + user: "0:0" # otherwise the persistent data directory is not writable env_file: - ../env.production - env.production + - env.secrets environment: DB_VENDOR: MYSQL DB_ADDR: mysql @@ -28,9 +30,11 @@ services: DB_USER: keycloak DB_PASSWORD: password KEYCLOAK_ADMIN: admin + # KEYCLOAK_ADMIN_PASSWORD should be set in env.secrets PROXY_ADDRESS_FORWARDING: 'true' volumes: - ./data/certs:/etc/x509/https + - ./data/keycloak:/opt/keycloak/data ports: - 8080:8080 depends_on: diff --git a/keycloak/env.production b/keycloak/env.production index 651fdf2..e69de29 100644 --- a/keycloak/env.production +++ b/keycloak/env.production @@ -1 +0,0 @@ -KEYCLOAK_ADMIN_PASSWORD=abcd@1234! diff --git a/keycloak/setup b/keycloak/setup index 344fc00..9c8bccf 100755 --- a/keycloak/setup +++ b/keycloak/setup @@ -6,6 +6,7 @@ DIRNAME="$(dirname $0)" cd "$DIRNAME" source ../env.production source ./env.production +source ./env.secrets info "logging into server" sudo docker-compose exec keycloak \ diff --git a/mastodon/docker-compose.yaml b/mastodon/docker-compose.yaml index c6c2363..2639e96 100644 --- a/mastodon/docker-compose.yaml +++ b/mastodon/docker-compose.yaml @@ -46,7 +46,7 @@ services: soft: -1 hard: -1 - web: + mastodon: image: tootsuite/mastodon restart: always env_file: @@ -70,7 +70,6 @@ services: - ./data/system:/mastodon/public/system streaming: - build: . image: tootsuite/mastodon restart: always env_file: @@ -91,7 +90,6 @@ services: - redis sidekiq: - build: . image: tootsuite/mastodon restart: always env_file: diff --git a/mastodon/env.production b/mastodon/env.production index 4b40eb1..e420cd0 100644 --- a/mastodon/env.production +++ b/mastodon/env.production @@ -14,7 +14,7 @@ # ---------- # This identifies your server and cannot be changed safely later # ---------- -LOCAL_DOMAIN=social.hackerspace.zone +# LOCAL_DOMAIN is set in env.secrets #WEB_DOMAIN=social.example.com # Redis @@ -77,12 +77,10 @@ OMNIAUTH_ONLY=true # OIDC supported since https://github.com/mastodon/mastodon/pull/16221 OIDC_ENABLED=true OIDC_PROMPT=Keycloak -OIDC_DISPLAY_NAME=hackerspace.zone -OIDC_ISSUER=https://login.hackerspace.zone/realms/hackerspace -OIDC_REDIRECT_URI=https://social.hackerspace.zone/auth/auth/openid_connect/callback OIDC_DISCOVERY=true OIDC_SCOPE=openid,profile OIDC_UID_FIELD=preferred_username OIDC_CLIENT_ID=mastodon OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true +# OIDC URLs are in env.secrets since they require env expansion # OIDC_CLIENT_SECRET is in env.secrets diff --git a/mastodon/setup b/mastodon/setup index d88ff56..2464e8f 100755 --- a/mastodon/setup +++ b/mastodon/setup @@ -18,40 +18,39 @@ OTP_SECRET=000000 OIDC_CLIENT_SECRET=000000 EOF +# have to bring it all down before we touch the files +docker-compose down + if [ -z "$MASTODON_SKIP_DB_INIT" ]; then info "configuring mastodon" - sudo docker-compose run web \ + sudo docker-compose run --rm mastodon \ rails db:setup \ || die "unable to login" fi -# now create the real secrets file -echo > env.secrets "# DO NOT CHECK IN" +OIDC_CLIENT_SECRET="$(openssl rand -hex 32)" + +# now create the real secrets file, +# along with some parameters that should be in the environment +cat < env.secrets +# DO NOT CHECK IN +LOCAL_DOMAIN=$MASTODON_HOSTNAME +OIDC_DISPLAY_NAME=$REALM +OIDC_ISSUER=https://$KEYCLOAK_HOSTNAME/realms/$REALM +OIDC_REDIRECT_URI=https://$MASTODON_HOSTNAME/auth/auth/openid_connect/callback +OIDC_CLIENT_SECRET=$OIDC_CLIENT_SECRET +SECRET_KEY_BASE=$(openssl rand -hex 32) +OTP_SECRET=$(openssl rand -hex 32) +EOF -sudo docker-compose run web \ +docker-compose run --rm mastodon \ rails mastodon:webpush:generate_vapid_key \ >> env.secrets \ || die "unable to generate vapid key" -echo "SECRET_KEY_BASE=$(openssl rand -hex 32)" >> env.secrets -echo "OTP_SECRET=$(openssl rand -hex 32)" >> env.secrets -CLIENT_SECRET="$(openssl rand -hex 32)" -echo "OIDC_CLIENT_SECRET=$CLIENT_SECRET" >> env.secrets - -# create the keycloak side of the secret -cd ../keycloak -source env.production - -sudo docker-compose exec -T keycloak \ - /opt/keycloak/bin/kcadm.sh \ - create clients \ - --server http://localhost:8080/ \ - --user admin \ - --password "$KEYCLOAK_ADMIN_PASSWORD" \ - --realm master \ - -r "$REALM" \ - -f - <&2 "$@" ; exit 1 ; } DIRNAME="$(dirname $0)" cd "$DIRNAME" -[ -r env.production ] && source env.production -[ -r ../env.production ] && source ../env.production +source ../env.production || die "no top level env?" +source env.production || die "no local env?" -sudo docker-compose exec -u www-data -T nextcloud \ - ./occ app:install sociallogin \ -|| die "unable to install sociallogin app" +if [ ! -r "env.secrets" ]; then + NEXTCLOUD_CLIENT_SECRET="$(openssl rand -hex 32)" + NEXTCLOUD_ADMIN_PASSWORD="$(openssl rand -hex 4)" -sudo docker-compose exec -u www-data -T nextcloud \ - ./occ config:app:set sociallogin prevent_create_email_exists --value=1 \ -|| die "unable to config sociallogin" - -sudo docker-compose exec -u www-data -T nextcloud \ - ./occ config:app:set sociallogin update_profile_on_login --value=1 \ -|| die "unable to config sociallogin" + echo "Generating secrets: admin password $NEXTCLOUD_ADMIN_PASSWORD" + cat < env.secrets +# Do not check in! +NEXTCLOUD_ADMIN_PASSWORD=$NEXTCLOUD_ADMIN_PASSWORD +NEXTCLOUD_TRUSTED_DOMAINS=$NEXTCLOUD_HOSTNAME +NEXTCLOUD_CLIENT_SECRET=$NEXTCLOUD_CLIENT_SECRET +EOF +else + source env.secrets || die "no secret env?" +fi BASE="https://$KEYCLOAK_HOSTNAME/realms/$REALM/protocol/openid-connect" -SECRET="$(openssl rand -hex 20)" PROVIDER="$(jq -c . <&2 "$@" ; exit 1 ; } +DIRNAME="$(dirname $0)" +cd "$DIRNAME" + source ../env.production source ./env.production -domain_args="-d $DOMAIN_NAME,$KEYCLOAK_HOSTNAME,$HEDGEDOC_HOSTNAME,$MASTODON_HOSTNAME,$NEXTCLOUD_HOSTNAME" +domain_args="-d $DOMAIN_NAME,$KEYCLOAK_HOSTNAME,$HEDGEDOC_HOSTNAME,$MASTODON_HOSTNAME,$NEXTCLOUD_HOSTNAME,$GRAFANA_HOSTNAME" rsa_key_size=2048 set -x -# move the old live directory away -rm -rf data/certbot/conf/live.old -mv data/certbot/conf/live data/certbot/conf/live.old +# move the temp live directory away if +# this is the first time we've run anything here +if [ ! -d "data/certbot/conf/accounts" ]; then + echo "deleting temp keys" + rm -rf data/certbot/conf/live +fi docker-compose run --rm certbot \ - certonly --webroot -w /var/www/certbot \ - $staging_arg \ + certonly \ + --webroot \ + --webroot-path /var/www/certbot \ --email "admin@$DOMAIN_NAME" \ - --rsa-key-size $rsa_key_size \ + --rsa-key-size "$rsa_key_size" \ --agree-tos \ --no-eff-email \ --force-renewal \ diff --git a/nginx/setup b/nginx/setup index 583f466..973d657 100755 --- a/nginx/setup +++ b/nginx/setup @@ -1,28 +1,39 @@ #!/bin/bash die() { echo >&2 "$@" ; exit 1 ; } -ENV=env.production -if [ ! -r "$ENV" ]; then - die "$ENV: not found?" -fi +DIRNAME="$(dirname $0)" +cd "$DIRNAME" -source ../env.production -source env.production +source ../env.production || die "no top level env" +source env.production || die "no local env" if [ -z "${DOMAIN_NAME}" ]; then die "DOMAIN_NAME not set" fi +docker-compose down + certdir="data/certbot/conf/live/${DOMAIN_NAME}" mkdir -p "$certdir" || die "$certdir: unable to make" -openssl req \ - -x509 \ - -newkey rsa:2048 \ - -keyout "$certdir/privkey.pem" \ - -out "$certdir/fullchain.pem" \ - -sha256 \ - -nodes \ - -days 365 \ - -subj "/CN=${DOMAIN_NAME}'" \ -|| die "$certdir/privkey.pem: unable to create temp key" +if [ ! -r "$certdir/privkey.pem" ]; then + openssl req \ + -x509 \ + -newkey rsa:2048 \ + -keyout "$certdir/privkey.pem" \ + -out "$certdir/fullchain.pem" \ + -sha256 \ + -nodes \ + -days 365 \ + -subj "/CN=${DOMAIN_NAME}'" \ + || die "$certdir/privkey.pem: unable to create temp key" +fi + +docker-compose up -d || die "unable to bring up nginx" + +echo "SLEEPING..." +sleep 10 + +./certbot-renew || die "unable to create certs" + +