mirror of
https://gerrit.hackerspace.pl/hscloud
synced 2025-01-21 21:13:53 +00:00
app/codehosting: forgejo deployment
Change-Id: Icfe6e0b17932a3248e1bdb807f431c59c48430de Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1685 Reviewed-by: q3k <q3k@hackerspace.pl>
This commit is contained in:
parent
f1dbac29a1
commit
3a3b425ddf
9 changed files with 587 additions and 1 deletions
26
app/codehosting/README.md
Normal file
26
app/codehosting/README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Hackerspace Code Hosting deployment
|
||||
|
||||
"Code Hosting service" below means Forgejo.
|
||||
|
||||
Due to certain specific requirements our deployment is a little customized.
|
||||
|
||||
While we prefer users to use SSO/OpenID Connect for authentication, we also
|
||||
want code hosting service to be aware of all active users to correctly
|
||||
synchronize account access and SSH keys. When running with both LDAP and OpenID
|
||||
Connect integration enabled users are automatically created in a local database
|
||||
based on LDAP source, however OpenID Connect identity is not automatically bound
|
||||
to LDAP users. This causes code hosting service to still show a password-based
|
||||
authentication form in order to join the two identities.
|
||||
|
||||
Workaround for this in our case is a SQL trigger function that automatically
|
||||
creates an OpenID Connect -> LDAP identity binding injected directly into code
|
||||
hosting service's PostgreSQL database. This trigger can be reviewed in
|
||||
`create-oidc-binding.sql` file here. For this to work correctly
|
||||
auto-registration needs to be disabled for OpenID Connect integration, in case
|
||||
some new user attempts to log in before code hosting service runs external
|
||||
users synchronization job.
|
||||
|
||||
LDAP users synchronization job has been adjusted to run every 10 minutes. (in
|
||||
contrast to default 24h, see `app.ini.template`)
|
||||
|
||||
Explore page has users listing disabled. Email and name display is disabled.
|
98
app/codehosting/app.ini.template
Normal file
98
app/codehosting/app.ini.template
Normal file
|
@ -0,0 +1,98 @@
|
|||
APP_NAME = $APP_NAME
|
||||
RUN_MODE = $RUN_MODE
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
|
||||
[server]
|
||||
APP_DATA_PATH = /data/gitea
|
||||
DOMAIN = $DOMAIN
|
||||
SSH_DOMAIN = $SSH_DOMAIN
|
||||
HTTP_PORT = $HTTP_PORT
|
||||
ROOT_URL = $ROOT_URL
|
||||
START_SSH_SERVER = true
|
||||
DISABLE_SSH = $DISABLE_SSH
|
||||
SSH_PORT = $SSH_PORT
|
||||
SSH_LISTEN_PORT = $SSH_LISTEN_PORT
|
||||
LFS_START_SERVER = $LFS_START_SERVER
|
||||
OFFLINE_MODE = $OFFLINE_MODE
|
||||
LANDING_PAGE = explore
|
||||
|
||||
[lfs]
|
||||
PATH = /data/git/lfs
|
||||
|
||||
[database]
|
||||
PATH = /data/gitea/gitea.db
|
||||
DB_TYPE = $DB_TYPE
|
||||
HOST = $DB_HOST
|
||||
NAME = $DB_NAME
|
||||
USER = $DB_USER
|
||||
PASSWD = $DB_PASSWD
|
||||
|
||||
[storage]
|
||||
STORAGE_TYPE = minio
|
||||
|
||||
MINIO_ENDPOINT = $MINIO_ENDPOINT
|
||||
MINIO_ACCESS_KEY_ID = $MINIO_ACCESS_KEY_ID
|
||||
MINIO_SECRET_ACCESS_KEY = $MINIO_SECRET_ACCESS_KEY
|
||||
MINIO_BUCKET = $MINIO_BUCKET
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /data/gitea/avatars
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
|
||||
|
||||
[attachment]
|
||||
PATH = /data/gitea/attachments
|
||||
|
||||
[log]
|
||||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = $INSTALL_LOCK
|
||||
SECRET_KEY = $SECRET_KEY
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = $DISABLE_REGISTRATION
|
||||
REQUIRE_SIGNIN_VIEW = $REQUIRE_SIGNIN_VIEW
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = $ALLOW_ONLY_EXTERNAL_REGISTRATION
|
||||
|
||||
[service.explore]
|
||||
DISABLE_USERS_PAGE = true
|
||||
|
||||
[ui]
|
||||
SHOW_USER_EMAIL = false
|
||||
|
||||
[oauth2_client]
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_AUTO_REGISTRATION = false
|
||||
USERNAME = userid
|
||||
ACCOUNT_LINKING = auto
|
||||
|
||||
[cron.sync_external_users]
|
||||
SCHEDULE = @every 10m
|
||||
RUN_AT_START = true
|
||||
|
||||
[i18n]
|
||||
LANGS = en-US,pl-PL
|
||||
NAMES = English,Polski
|
||||
|
||||
[mailer]
|
||||
ENABLED = true
|
||||
FROM = $MAILER_FROM
|
||||
PROTOCOL = smtps
|
||||
SMTP_ADDR = $MAILER_HOST
|
||||
SMTP_PORT = $MAILER_PORT
|
||||
USER = $MAILER_USER
|
||||
PASSWD = $MAILER_PASSWORD
|
19
app/codehosting/bootstrap-auth.sh
Normal file
19
app/codehosting/bootstrap-auth.sh
Normal file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script runs in an initContainer (once, using /data/.gitea_bootstrap_done
|
||||
# as a witness file) and is responsible for setting up and configuring:
|
||||
# * initial admin user
|
||||
# * hswaw OpenID Connect provider
|
||||
# * hswaw LDAP user database
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
if [[ -f '/data/.gitea_bootstrap_done' ]]; then
|
||||
echo '/data/.gitea_bootstrap_done exists, not doing anything'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
/app/gitea/gitea admin user create --username bofh --password ${ADMIN_PASSWORD} --email bofh@hackerspace.pl --admin --must-change-password=false
|
||||
/app/gitea/gitea admin auth add-oauth --name hswaw-oidc --provider openidConnect --key ${SSO_CLIENT_ID} --secret ${SSO_CLIENT_SECRET} --auto-discover-url https://sso.hackerspace.pl/.well-known/openid-configuration
|
||||
/app/gitea/gitea admin auth add-ldap --name hswaw-ldap --active --security-protocol ldaps --host ldap.hackerspace.pl --port 636 --bind-dn ${LDAP_BIND_DN} --bind-password ${LDAP_BIND_PASSWORD} --user-search-base "ou=People,dc=hackerspace,dc=pl" --user-filter "(&(objectclass=hsMember)(uid=%[1]s)(|(memberOf=cn=fatty,ou=Group,dc=hackerspace,dc=pl)(memberOf=cn=starving,ou=Group,dc=hackerspace,dc=pl)(memberOf=cn=potato,ou=Group,dc=hackerspace,dc=pl)))" --admin-filter "(memberOf=cn=staff,ou=Group,dc=hackerspace,dc=pl)" --username-attribute uid --email-attribute mail --public-ssh-key-attribute sshPublicKey --synchronize-users
|
||||
touch /data/.gitea_bootstrap_done
|
23
app/codehosting/create-oidc-binding.sql
Normal file
23
app/codehosting/create-oidc-binding.sql
Normal file
|
@ -0,0 +1,23 @@
|
|||
-- This trigger automatically ensures an openid connect identity is bound to an
|
||||
-- equivalent LDAP account created by Gitea/Forgejo.
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE OR REPLACE FUNCTION upsert_oidc_external_users ()
|
||||
RETURNS TRIGGER
|
||||
AS $$
|
||||
BEGIN
|
||||
-- 1 is OpenID Connect login source ID
|
||||
-- 2 is LDAP login source ID
|
||||
INSERT INTO external_login_user (external_id, user_id, login_source_id) SELECT name, id, 1 FROM "user" WHERE login_source = 2 ON CONFLICT DO NOTHING;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
|
||||
DROP TRIGGER IF EXISTS upsert_oidc_external_users ON "user";
|
||||
CREATE TRIGGER upsert_oidc_external_users AFTER INSERT OR UPDATE ON "user" EXECUTE PROCEDURE upsert_oidc_external_users();
|
||||
|
||||
-- Force trigger run
|
||||
UPDATE "user" SET name = name WHERE FALSE;
|
||||
|
||||
COMMIT;
|
69
app/codehosting/entrypoint.sh
Normal file
69
app/codehosting/entrypoint.sh
Normal file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
|
||||
for FOLDER in /data/gitea/log /data/git /data/ssh; do
|
||||
mkdir -p ${FOLDER}
|
||||
done
|
||||
|
||||
if [ ! -d /data/git/.ssh ]; then
|
||||
mkdir -p /data/git/.ssh
|
||||
fi
|
||||
|
||||
if [ ! -f /data/git/.ssh/environment ]; then
|
||||
echo "GITEA_CUSTOM=$GITEA_CUSTOM" >| /data/git/.ssh/environment
|
||||
|
||||
elif ! grep -q "^GITEA_CUSTOM=$GITEA_CUSTOM$" /data/git/.ssh/environment; then
|
||||
sed -i /^GITEA_CUSTOM=/d /data/git/.ssh/environment
|
||||
echo "GITEA_CUSTOM=$GITEA_CUSTOM" >> /data/git/.ssh/environment
|
||||
fi
|
||||
|
||||
if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then
|
||||
mkdir -p ${GITEA_CUSTOM}/conf
|
||||
|
||||
# Set INSTALL_LOCK to true only if SECRET_KEY is not empty and
|
||||
# INSTALL_LOCK is empty
|
||||
if [ -n "$SECRET_KEY" ] && [ -z "$INSTALL_LOCK" ]; then
|
||||
INSTALL_LOCK=true
|
||||
fi
|
||||
|
||||
# Substitude the environment variables in the template
|
||||
env -i \
|
||||
APP_NAME="${APP_NAME:-"Gitea: Git with a cup of tea"}" \
|
||||
RUN_MODE="${RUN_MODE:-"dev"}" \
|
||||
DOMAIN="${DOMAIN:-"localhost"}" \
|
||||
SSH_DOMAIN="${SSH_DOMAIN:-"localhost"}" \
|
||||
HTTP_PORT="${HTTP_PORT:-"3000"}" \
|
||||
ROOT_URL="${ROOT_URL:-""}" \
|
||||
DISABLE_SSH="${DISABLE_SSH:-"false"}" \
|
||||
SSH_PORT="${SSH_PORT:-"22"}" \
|
||||
SSH_LISTEN_PORT="${SSH_LISTEN_PORT:-"${SSH_PORT}"}" \
|
||||
LFS_START_SERVER="${LFS_START_SERVER:-"false"}" \
|
||||
DB_TYPE="${DB_TYPE:-"sqlite3"}" \
|
||||
DB_HOST="${DB_HOST:-"localhost:3306"}" \
|
||||
DB_NAME="${DB_NAME:-"gitea"}" \
|
||||
DB_USER="${DB_USER:-"root"}" \
|
||||
DB_PASSWD="${DB_PASSWD:-""}" \
|
||||
INSTALL_LOCK="${INSTALL_LOCK:-"false"}" \
|
||||
DISABLE_REGISTRATION="${DISABLE_REGISTRATION:-"false"}" \
|
||||
REQUIRE_SIGNIN_VIEW="${REQUIRE_SIGNIN_VIEW:-"false"}" \
|
||||
SECRET_KEY="${SECRET_KEY:-""}" \
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION="${ALLOW_ONLY_EXTERNAL_REGISTRATION:-"false"}" \
|
||||
OFFLINE_MODE="${OFFLINE_MODE:-"true"}" \
|
||||
MINIO_ENDPOINT="${MINIO_ENDPOINT:-""}" \
|
||||
MINIO_ACCESS_KEY_ID="${MINIO_ACCESS_KEY_ID:-""}" \
|
||||
MINIO_SECRET_ACCESS_KEY="${MINIO_SECRET_ACCESS_KEY:-""}" \
|
||||
MINIO_BUCKET="${MINIO_BUCKET:-""}" \
|
||||
MAILER_FROM="${MAILER_FROM:-""}" \
|
||||
MAILER_HOST="${MAILER_HOST:-""}" \
|
||||
MAILER_PORT="${MAILER_PORT:-""}" \
|
||||
MAILER_USER="${MAILER_USER:-""}" \
|
||||
MAILER_PASSWORD="${MAILER_PASSWORD:-""}" \
|
||||
envsubst < /etc/templates/app.ini > ${GITEA_CUSTOM}/conf/app.ini
|
||||
cat ${GITEA_CUSTOM}/conf/app.ini
|
||||
fi
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
exec "$@"
|
||||
else
|
||||
exec /app/gitea/gitea web
|
||||
fi
|
||||
|
253
app/codehosting/forgejo.libsonnet
Normal file
253
app/codehosting/forgejo.libsonnet
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
|
||||
Deploy a Forgejo instance with PostgreSQL database and additional PV for git data.
|
||||
Pre-provision the secrets with:
|
||||
|
||||
kubectl -n $KUBE_NAMESPACE create secret generic forgejo \
|
||||
--from-literal=postgres_password=$(pwgen -s 24 1) \
|
||||
--from-literal=secret_key=$(pwgen -s 128 1) \
|
||||
--from-literal=admin_password=$(pwgen -s 128 1) \
|
||||
--from-literal=oauth2_client_id=$SSO_CLIENT_ID \
|
||||
--from-literal=oauth2_client_secret=$SSO_CLIENT_SECRET \
|
||||
--from-literal=ldap_bind_dn=$LDAP_BIND_DN \
|
||||
--from-literal=ldap_bind_password=$LDAP_BIND_PASSWORD \
|
||||
--from-literal=smtp_password=$SMTP_PASSWORD
|
||||
|
||||
Import objectstore secret:
|
||||
|
||||
ceph_ns=ceph-waw3; ceph_pool=waw-hdd-redundant-3
|
||||
kubectl -n $ceph_ns get secrets rook-ceph-object-user-${ceph_pool}-object-codehosting -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -f - -n $KUBE_NAMESPACE
|
||||
|
||||
Import oidc auth trigger:
|
||||
|
||||
kubectl -n $KUBE_NAMESPACE exec deploy/postgres -i -- psql -U forgejo forgejo < create-oidc-binding.sql
|
||||
|
||||
*/
|
||||
|
||||
local kube = import "../../kube/kube.libsonnet";
|
||||
local postgres = import "../../kube/postgres.libsonnet";
|
||||
|
||||
{
|
||||
local forgejo = self,
|
||||
local cfg = forgejo.cfg,
|
||||
cfg:: {
|
||||
namespace: error "namespace must be set",
|
||||
prefix: "",
|
||||
|
||||
image: "codeberg.org/forgejo/forgejo:1.20.5-0",
|
||||
storageClassName: "waw-hdd-redundant-3",
|
||||
storageSize: { git: "200Gi" },
|
||||
|
||||
admin_username: error "admin_username must be set",
|
||||
admin_email: error "admin_email must be set",
|
||||
|
||||
# Forgejo configuration, roughly representing the structure of app.ini
|
||||
instanceName: error "instanceName (e.g. 'Warsaw Hackerspace Forgejo') must be set",
|
||||
runMode: "prod",
|
||||
server: {
|
||||
domain: error "domain (e.g. git.hackerspace.pl) must be set",
|
||||
sshDomain: cfg.server.domain,
|
||||
rootURL: "https://" + cfg.server.domain + "/",
|
||||
offlineMode: "true",
|
||||
},
|
||||
security: {
|
||||
installLock: "true",
|
||||
},
|
||||
service: {
|
||||
disableRegistration: "false",
|
||||
allowOnlyExternalRegistration: "true",
|
||||
},
|
||||
|
||||
s3: {
|
||||
endpoint: "rook-ceph-rgw-waw-hdd-redundant-3-object.ceph-waw3.svc:80", #{ secretKeyRef: {name: "rook-ceph-object-user-waw-hdd-redundant-3-object-codehosting", key: "Endpoint" } },
|
||||
accessKey: { secretKeyRef: {name: "rook-ceph-object-user-waw-hdd-redundant-3-object-codehosting", key: "AccessKey" } },
|
||||
secretKey: { secretKeyRef: {name: "rook-ceph-object-user-waw-hdd-redundant-3-object-codehosting", key: "SecretKey" } },
|
||||
bucket: "codehosting",
|
||||
},
|
||||
|
||||
mailer: {
|
||||
from: "forgejo@hackerspace.pl",
|
||||
host: "mail.hackerspace.pl",
|
||||
port: 465,
|
||||
user: "forgejo",
|
||||
password: { secretKeyRef: { name: "forgejo", key: "smtp_password" } },
|
||||
},
|
||||
},
|
||||
|
||||
name(suffix):: cfg.prefix + suffix,
|
||||
ns: kube.Namespace(cfg.namespace),
|
||||
|
||||
postgres: postgres {
|
||||
cfg+: {
|
||||
namespace: cfg.namespace,
|
||||
appName: "forgejo",
|
||||
database: "forgejo",
|
||||
username: "forgejo",
|
||||
password: { secretKeyRef: { name: "forgejo", key: "postgres_password" } },
|
||||
storageClassName: cfg.storageClassName,
|
||||
},
|
||||
},
|
||||
|
||||
configMap: forgejo.ns.Contain(kube.ConfigMap(forgejo.name("forgejo"))) {
|
||||
data: {
|
||||
"app.ini.template": importstr 'app.ini.template',
|
||||
"entrypoint.sh": importstr 'entrypoint.sh',
|
||||
"bootstrap-auth.sh": importstr 'bootstrap-auth.sh',
|
||||
},
|
||||
},
|
||||
|
||||
dataVolume: forgejo.ns.Contain(kube.PersistentVolumeClaim(forgejo.name("forgejo"))) {
|
||||
spec+: {
|
||||
storageClassName: cfg.storageClassName,
|
||||
accessModes: [ "ReadWriteOnce" ],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: cfg.storageSize.git,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
forgejoCustom: forgejo.ns.Contain(kube.ConfigMap(forgejo.name("forgejo-custom"))) {
|
||||
data: {
|
||||
"signin_inner.tmpl": importstr 'signin_inner.tmpl',
|
||||
},
|
||||
},
|
||||
|
||||
statefulSet: forgejo.ns.Contain(kube.StatefulSet(forgejo.name("forgejo"))) {
|
||||
spec+: {
|
||||
replicas: 1,
|
||||
template+: {
|
||||
spec+: {
|
||||
securityContext: {
|
||||
runAsUser: 1000,
|
||||
runAsGroup: 1000,
|
||||
fsGroup: 1000,
|
||||
},
|
||||
volumes_: {
|
||||
configmap: kube.ConfigMapVolume(forgejo.configMap),
|
||||
custom: kube.ConfigMapVolume(forgejo.forgejoCustom),
|
||||
data: kube.PersistentVolumeClaimVolume(forgejo.dataVolume),
|
||||
empty: kube.EmptyDirVolume(),
|
||||
},
|
||||
containers_: {
|
||||
server: kube.Container(forgejo.name("forgejo")) {
|
||||
image: cfg.image,
|
||||
command: [ "bash", "/usr/bin/entrypoint" ],
|
||||
ports_: {
|
||||
server: { containerPort: 3000 },
|
||||
ssh: { containerPort: 22 },
|
||||
},
|
||||
readinessProbe: {
|
||||
tcpSocket: {
|
||||
port: "server",
|
||||
},
|
||||
initialDelaySeconds: 5,
|
||||
periodSeconds: 5,
|
||||
successThreshold: 1,
|
||||
failureThreshold: 3
|
||||
},
|
||||
env_: {
|
||||
APP_NAME: cfg.instanceName,
|
||||
RUN_MODE: cfg.runMode,
|
||||
INSTALL_LOCK: cfg.security.installLock,
|
||||
SECRET_KEY: { secretKeyRef: { name: "forgejo", key: "secret_key" } },
|
||||
DB_TYPE: "postgres",
|
||||
DB_HOST: "postgres:5432",
|
||||
DB_USER: forgejo.postgres.cfg.username,
|
||||
DB_PASSWD: forgejo.postgres.cfg.password,
|
||||
DB_NAME: forgejo.postgres.cfg.appName,
|
||||
DOMAIN: cfg.server.domain,
|
||||
SSH_DOMAIN: cfg.server.sshDomain,
|
||||
SSH_LISTEN_PORT: "2222",
|
||||
ROOT_URL: forgejo.cfg.server.rootURL,
|
||||
DISABLE_REGISTRATION: cfg.service.disableRegistration,
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION: cfg.service.allowOnlyExternalRegistration,
|
||||
OFFLINE_MODE: cfg.server.offlineMode,
|
||||
USER_UID: "1000",
|
||||
USER_GID: "1000",
|
||||
GITEA_CUSTOM: "/custom",
|
||||
MINIO_ENDPOINT: cfg.s3.endpoint,
|
||||
MINIO_BUCKET: cfg.s3.bucket,
|
||||
MINIO_ACCESS_KEY_ID: cfg.s3.accessKey,
|
||||
MINIO_SECRET_ACCESS_KEY: cfg.s3.secretKey,
|
||||
MAILER_FROM: cfg.mailer.from,
|
||||
MAILER_HOST: cfg.mailer.host,
|
||||
MAILER_PORT: cfg.mailer.port,
|
||||
MAILER_USER: cfg.mailer.user,
|
||||
MAILER_PASSWORD: cfg.mailer.password,
|
||||
},
|
||||
volumeMounts: [
|
||||
{ name: "configmap", subPath: "entrypoint.sh", mountPath: "/usr/bin/entrypoint" },
|
||||
{ name: "configmap", subPath: "app.ini.template", mountPath: "/etc/templates/app.ini" },
|
||||
{ name: "data", mountPath: "/data" },
|
||||
{ name: "empty", mountPath: "/custom" },
|
||||
{ name: "custom", subPath: "signin_inner.tmpl", mountPath: "/custom/templates/user/auth/signin_inner.tmpl" },
|
||||
],
|
||||
},
|
||||
},
|
||||
initContainers: [
|
||||
kube.Container(forgejo.name("forgejo-dbmigrate")) {
|
||||
image: forgejo.statefulSet.spec.template.spec.containers_.server.image,
|
||||
command: [ "bash", "/usr/bin/entrypoint", "/app/gitea/gitea", "migrate" ],
|
||||
env_: forgejo.statefulSet.spec.template.spec.containers_.server.env_,
|
||||
volumeMounts: forgejo.statefulSet.spec.template.spec.containers_.server.volumeMounts,
|
||||
},
|
||||
kube.Container(forgejo.name("forgejo-bootstrap-auth")) {
|
||||
image: forgejo.statefulSet.spec.template.spec.containers_.server.image,
|
||||
command: [
|
||||
"bash", "/bootstrap-auth.sh"
|
||||
],
|
||||
env_: forgejo.statefulSet.spec.template.spec.containers_.server.env_ + {
|
||||
ADMIN_PASSWORD: { secretKeyRef: { name: "forgejo", key: "admin_password" } },
|
||||
SSO_CLIENT_ID: { secretKeyRef: { name: "forgejo", key: "oauth2_client_id" } },
|
||||
SSO_CLIENT_SECRET: { secretKeyRef: { name: "forgejo", key: "oauth2_client_secret" } },
|
||||
LDAP_BIND_DN: { secretKeyRef: { name: "forgejo", key: "ldap_bind_dn" } },
|
||||
LDAP_BIND_PASSWORD: { secretKeyRef: { name: "forgejo", key: "ldap_bind_password" } },
|
||||
},
|
||||
volumeMounts: forgejo.statefulSet.spec.template.spec.containers_.server.volumeMounts + [
|
||||
{ name: "configmap", subPath: "bootstrap-auth.sh", mountPath: "/bootstrap-auth.sh" },
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
svc: forgejo.ns.Contain(kube.Service(forgejo.name("forgejo"))) {
|
||||
target_pod:: forgejo.statefulSet.spec.template,
|
||||
spec+: {
|
||||
ports: [
|
||||
{ name: "server", port: 80, targetPort: 3000, protocol: "TCP" },
|
||||
{ name: "ssh", port: 22, targetPort: 2222, protocol: "TCP" },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
ingress: forgejo.ns.Contain(kube.Ingress(forgejo.name("forgejo"))) {
|
||||
metadata+: {
|
||||
annotations+: {
|
||||
"kubernetes.io/tls-acme": "true",
|
||||
"cert-manager.io/cluster-issuer": "letsencrypt-prod",
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
|
||||
},
|
||||
},
|
||||
spec+: {
|
||||
tls: [
|
||||
{ hosts: [cfg.server.domain], secretName: forgejo.name("acme") },
|
||||
],
|
||||
rules: [
|
||||
{
|
||||
host: cfg.server.domain,
|
||||
http: {
|
||||
paths: [
|
||||
{ path: "/", backend: forgejo.svc.name_port },
|
||||
],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
}
|
20
app/codehosting/prod.jsonnet
Normal file
20
app/codehosting/prod.jsonnet
Normal file
|
@ -0,0 +1,20 @@
|
|||
local kube = import "../../kube/kube.libsonnet";
|
||||
local forgejo = import "forgejo.libsonnet";
|
||||
{
|
||||
#namespace: kube.Namespace("forgejo-prod"),
|
||||
|
||||
forgejo: forgejo {
|
||||
cfg+: {
|
||||
namespace: "codehosting-prod",
|
||||
prefix: "",
|
||||
|
||||
admin_username: "bofh",
|
||||
admin_email: "bofh@hackerspace.pl",
|
||||
|
||||
instanceName: "Warsaw Hackerspace Codehosting",
|
||||
server+: {
|
||||
domain: "git.hackerspace.pl",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
77
app/codehosting/signin_inner.tmpl
Normal file
77
app/codehosting/signin_inner.tmpl
Normal file
|
@ -0,0 +1,77 @@
|
|||
<!-- Mirrored from https://codeberg.org/forgejo/forgejo/raw/tag/v1.20.5-0/templates/user/auth/signin_inner.tmpl with gt-hidden adjustment to hide login form -->
|
||||
|
||||
{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn)}}
|
||||
{{template "base/alert" .}}
|
||||
{{end}}
|
||||
<h4 class="ui top attached header center">
|
||||
{{if .LinkAccountMode}}
|
||||
{{.locale.Tr "auth.oauth_signin_title"}}
|
||||
{{else}}
|
||||
{{.locale.Tr "auth.login_userpass"}}
|
||||
{{end}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<form class="ui form" action="{{.SignInLink}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="gt-hidden">
|
||||
<div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
||||
<label for="user_name">{{.locale.Tr "home.uname_holder"}}</label>
|
||||
<input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required>
|
||||
</div>
|
||||
{{if or (not .DisablePassword) .LinkAccountMode}}
|
||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
||||
<label for="password">{{.locale.Tr "password"}}</label>
|
||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="current-password" required>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .LinkAccountMode}}
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<div class="ui checkbox">
|
||||
<label>{{.locale.Tr "auth.remember_me"}}</label>
|
||||
<input name="remember" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{template "user/auth/captcha" .}}
|
||||
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<button class="ui green button">
|
||||
{{if .LinkAccountMode}}
|
||||
{{.locale.Tr "auth.oauth_signin_submit"}}
|
||||
{{else}}
|
||||
{{.locale.Tr "sign_in"}}
|
||||
{{end}}
|
||||
</button>
|
||||
<a href="{{AppSubUrl}}/user/forgot_password">{{.locale.Tr "auth.forgot_password"}}</a>
|
||||
</div>
|
||||
|
||||
{{if .ShowRegistrationButton}}
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<a href="{{AppSubUrl}}/user/sign_up">{{.locale.Tr "auth.sign_up_now" | Str2html}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if and .OrderedOAuth2Names .OAuth2Providers}}
|
||||
<div class="ui horizontal divider gt-hidden">
|
||||
{{.locale.Tr "sign_in_or"}}
|
||||
</div>
|
||||
<div id="oauth2-login-navigator" class="gt-py-2">
|
||||
<div class="gt-df gt-fc gt-jc">
|
||||
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
||||
{{range $key := .OrderedOAuth2Names}}
|
||||
{{$provider := index $.OAuth2Providers $key}}
|
||||
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$key}}">
|
||||
{{$provider.IconHTML}}
|
||||
{{$.locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</form>
|
||||
</div>
|
|
@ -84,6 +84,7 @@ local policies = import "../../../kube/policies.libsonnet";
|
|||
tcp: env.maps.make("tcp-services") {
|
||||
data: {
|
||||
"22": "gerrit/gerrit:22",
|
||||
"222": "codehosting-prod/forgejo:22",
|
||||
}
|
||||
},
|
||||
udp: env.maps.make("udp-services"),
|
||||
|
@ -235,7 +236,7 @@ local policies = import "../../../kube/policies.libsonnet";
|
|||
},
|
||||
},
|
||||
|
||||
serviceGitea: kube.Service("ingress-nginx-gitea") {
|
||||
serviceCodehosting: kube.Service("ingress-nginx-codehosting") {
|
||||
metadata+: env.metadata,
|
||||
target:: env.deployment,
|
||||
spec+: {
|
||||
|
|
Loading…
Reference in a new issue