Grant Tailnet access and harden Zulip bootstrap
This commit is contained in:
parent
801e0fb419
commit
b8cad4c028
6 changed files with 90 additions and 9 deletions
|
|
@ -294,8 +294,8 @@ existing_application="$(
|
||||||
)"
|
)"
|
||||||
|
|
||||||
if [[ -n "$existing_application" ]]; then
|
if [[ -n "$existing_application" ]]; then
|
||||||
application_pk="existing"
|
application_pk="$(printf '%s\n' "$existing_application" | jq -r '.pk')"
|
||||||
api PATCH "/api/v3/core/applications/${application_slug}/" "$application_payload" >/dev/null
|
api PATCH "/api/v3/core/applications/${application_pk}/" "$application_payload" >/dev/null
|
||||||
else
|
else
|
||||||
create_application_result="$(
|
create_application_result="$(
|
||||||
api_with_status POST "/api/v3/core/applications/" "$application_payload"
|
api_with_status POST "/api/v3/core/applications/" "$application_payload"
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,12 @@ application_payload="$(
|
||||||
policy_engine_mode: .policy_engine_mode
|
policy_engine_mode: .policy_engine_mode
|
||||||
}'
|
}'
|
||||||
)"
|
)"
|
||||||
api PATCH "/api/v3/core/applications/${application_slug}/" "$application_payload" >/dev/null
|
application_pk="$(printf '%s\n' "$application" | jq -r '.pk // empty')"
|
||||||
|
if [[ -z "$application_pk" ]]; then
|
||||||
|
echo "error: could not resolve Authentik application primary key for ${application_slug}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
api PATCH "/api/v3/core/applications/${application_pk}/" "$application_payload" >/dev/null
|
||||||
|
|
||||||
group_pks_json="$(jq -cn --arg owner "$owner_group_pk" --arg admin "$admin_group_pk" --arg guest "$guest_group_pk" '[$owner, $admin, $guest]')"
|
group_pks_json="$(jq -cn --arg owner "$owner_group_pk" --arg admin "$admin_group_pk" --arg guest "$guest_group_pk" '[$owner, $admin, $guest]')"
|
||||||
user_pks_json="$(
|
user_pks_json="$(
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,7 @@ existing_application="$(
|
||||||
|
|
||||||
if [[ -n "$existing_application" ]]; then
|
if [[ -n "$existing_application" ]]; then
|
||||||
application_pk="$(printf '%s\n' "$existing_application" | jq -r '.pk')"
|
application_pk="$(printf '%s\n' "$existing_application" | jq -r '.pk')"
|
||||||
api PATCH "/api/v3/core/applications/${application_slug}/" "$application_payload" >/dev/null
|
api PATCH "/api/v3/core/applications/${application_pk}/" "$application_payload" >/dev/null
|
||||||
else
|
else
|
||||||
create_application_result="$(
|
create_application_result="$(
|
||||||
api_with_status POST "/api/v3/core/applications/" "$application_payload"
|
api_with_status POST "/api/v3/core/applications/" "$application_payload"
|
||||||
|
|
|
||||||
|
|
@ -344,8 +344,8 @@ existing_application="$(
|
||||||
)"
|
)"
|
||||||
|
|
||||||
if [[ -n "$existing_application" ]]; then
|
if [[ -n "$existing_application" ]]; then
|
||||||
application_pk="existing"
|
application_pk="$(printf '%s\n' "$existing_application" | jq -r '.pk')"
|
||||||
api PATCH "/api/v3/core/applications/${application_slug}/" "$application_payload" >/dev/null
|
api PATCH "/api/v3/core/applications/${application_pk}/" "$application_payload" >/dev/null
|
||||||
else
|
else
|
||||||
create_application_result="$(
|
create_application_result="$(
|
||||||
api_with_status POST "/api/v3/core/applications/" "$application_payload"
|
api_with_status POST "/api/v3/core/applications/" "$application_payload"
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,7 @@ in
|
||||||
googleLoginMode = "redirect";
|
googleLoginMode = "redirect";
|
||||||
userGroupName = contributors.groups.users;
|
userGroupName = contributors.groups.users;
|
||||||
adminGroupName = contributors.groups.admins;
|
adminGroupName = contributors.groups.admins;
|
||||||
|
tailscaleAccessGroupName = contributors.groups.users;
|
||||||
bootstrapUsers = bootstrapUsers;
|
bootstrapUsers = bootstrapUsers;
|
||||||
linearAcsUrl = "https://api.linear.app/auth/sso/d0ca13dc-ac41-4824-8aab-e0ca352fc3de/acs";
|
linearAcsUrl = "https://api.linear.app/auth/sso/d0ca13dc-ac41-4824-8aab-e0ca352fc3de/acs";
|
||||||
linearAudience = "https://auth.linear.app/sso/d0ca13dc-ac41-4824-8aab-e0ca352fc3de";
|
linearAudience = "https://auth.linear.app/sso/d0ca13dc-ac41-4824-8aab-e0ca352fc3de";
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,18 @@ in
|
||||||
description = "Operational Zulip administrator email.";
|
description = "Operational Zulip administrator email.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
realmName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Burrow";
|
||||||
|
description = "Initial Zulip organization name for single-tenant bootstrap.";
|
||||||
|
};
|
||||||
|
|
||||||
|
realmOwnerName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Burrow";
|
||||||
|
description = "Display name used for the initial Zulip organization owner.";
|
||||||
|
};
|
||||||
|
|
||||||
authentikDomain = lib.mkOption {
|
authentikDomain = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = config.services.burrow.authentik.domain;
|
default = config.services.burrow.authentik.domain;
|
||||||
|
|
@ -227,6 +239,7 @@ in
|
||||||
chmod 0600 ${lib.escapeShellArg "${cfg.dataDir}/secrets/email-password"}
|
chmod 0600 ${lib.escapeShellArg "${cfg.dataDir}/secrets/email-password"}
|
||||||
install -m 0444 ${lib.escapeShellArg cfg.memcachedPasswordFile} ${lib.escapeShellArg "${cfg.dataDir}/secrets/memcached-password"}
|
install -m 0444 ${lib.escapeShellArg cfg.memcachedPasswordFile} ${lib.escapeShellArg "${cfg.dataDir}/secrets/memcached-password"}
|
||||||
cat > ${lib.escapeShellArg "${cfg.dataDir}/rabbitmq.conf"} <<EOF
|
cat > ${lib.escapeShellArg "${cfg.dataDir}/rabbitmq.conf"} <<EOF
|
||||||
|
listeners.tcp.default = 0.0.0.0:5672
|
||||||
default_user = zulip
|
default_user = zulip
|
||||||
default_pass = "$(tr -d '\r\n' < ${lib.escapeShellArg cfg.rabbitmqPasswordFile})"
|
default_pass = "$(tr -d '\r\n' < ${lib.escapeShellArg cfg.rabbitmqPasswordFile})"
|
||||||
EOF
|
EOF
|
||||||
|
|
@ -311,6 +324,9 @@ EOF
|
||||||
path = [
|
path = [
|
||||||
pkgs.bash
|
pkgs.bash
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
|
pkgs.gawk
|
||||||
|
pkgs.gnugrep
|
||||||
|
pkgs.openssl
|
||||||
pkgs.podman
|
pkgs.podman
|
||||||
pkgs.podman-compose
|
pkgs.podman-compose
|
||||||
];
|
];
|
||||||
|
|
@ -334,13 +350,72 @@ EOF
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd ${lib.escapeShellArg cfg.dataDir}
|
cd ${lib.escapeShellArg cfg.dataDir}
|
||||||
|
|
||||||
|
compose() {
|
||||||
|
${pkgs.podman-compose}/bin/podman-compose -p burrow-zulip "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_rabbitmq() {
|
||||||
|
local attempts=0
|
||||||
|
while ! podman exec burrow-zulip_rabbitmq_1 rabbitmq-diagnostics -q ping >/dev/null 2>&1; do
|
||||||
|
attempts=$((attempts + 1))
|
||||||
|
if [ "$attempts" -ge 90 ]; then
|
||||||
|
echo "error: RabbitMQ did not become ready for Zulip bootstrap" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_zulip_volume_layout() {
|
||||||
|
local zulip_volume_mount
|
||||||
|
zulip_volume_mount="$(podman volume inspect burrow-zulip_zulip --format '{{.Mountpoint}}')"
|
||||||
|
install -d -m 0755 "$zulip_volume_mount/logs"
|
||||||
|
install -d -m 0755 "$zulip_volume_mount/logs/emails"
|
||||||
|
install -d -m 0700 "$zulip_volume_mount/secrets"
|
||||||
|
chown 1000:1000 "$zulip_volume_mount/logs" "$zulip_volume_mount/logs/emails" "$zulip_volume_mount/secrets"
|
||||||
|
|
||||||
|
if [ ! -s "$zulip_volume_mount/secrets/bootstrap-owner-password" ]; then
|
||||||
|
umask 077
|
||||||
|
openssl rand -base64 24 > "$zulip_volume_mount/secrets/bootstrap-owner-password"
|
||||||
|
fi
|
||||||
|
chown 1000:1000 "$zulip_volume_mount/secrets/bootstrap-owner-password"
|
||||||
|
chmod 0600 "$zulip_volume_mount/secrets/bootstrap-owner-password"
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap_realm_if_needed() {
|
||||||
|
local realm_exists
|
||||||
|
realm_exists="$(
|
||||||
|
compose run --rm --entrypoint bash zulip -lc \
|
||||||
|
"su zulip -c '/home/zulip/deployments/current/manage.py list_realms'" \
|
||||||
|
| awk '$NF == "https://${cfg.domain}" { print "yes" }'
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ -n "$realm_exists" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
export ZULIP_REALM_NAME=${lib.escapeShellArg cfg.realmName}
|
||||||
|
export ZULIP_ADMIN_EMAIL=${lib.escapeShellArg cfg.administratorEmail}
|
||||||
|
export ZULIP_OWNER_NAME=${lib.escapeShellArg cfg.realmOwnerName}
|
||||||
|
|
||||||
|
compose run --rm --entrypoint bash zulip -lc '
|
||||||
|
su zulip -c "/home/zulip/deployments/current/manage.py create_realm --string-id= --password-file /data/secrets/bootstrap-owner-password --automated \"$ZULIP_REALM_NAME\" \"$ZULIP_ADMIN_EMAIL\" \"$ZULIP_OWNER_NAME\""
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
if [ ! -e .initialized ]; then
|
if [ ! -e .initialized ]; then
|
||||||
${pkgs.podman-compose}/bin/podman-compose -p burrow-zulip pull
|
compose pull
|
||||||
${pkgs.podman-compose}/bin/podman-compose -p burrow-zulip run --rm zulip app:init
|
compose up -d database memcached rabbitmq redis
|
||||||
|
wait_for_rabbitmq
|
||||||
|
compose run --rm zulip app:init
|
||||||
touch .initialized
|
touch .initialized
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${pkgs.podman-compose}/bin/podman-compose -p burrow-zulip up -d
|
compose up -d database memcached rabbitmq redis
|
||||||
|
wait_for_rabbitmq
|
||||||
|
ensure_zulip_volume_layout
|
||||||
|
bootstrap_realm_if_needed
|
||||||
|
compose up -d zulip
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue