first commit

This commit is contained in:
2023-07-14 11:51:07 +02:00
commit 284dc650c4
101 changed files with 8629 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
# Source: gitea/charts/memcached/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-memcached
namespace: vynil-ci
labels:
app.kubernetes.io/name: memcached
helm.sh/chart: memcached-6.3.14
app.kubernetes.io/instance: gitea
app.kubernetes.io/managed-by: Helm
spec:
selector:
matchLabels:
app.kubernetes.io/name: memcached
app.kubernetes.io/instance: gitea
replicas: 1
strategy:
rollingUpdate: {}
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: memcached
helm.sh/chart: memcached-6.3.14
app.kubernetes.io/instance: gitea
app.kubernetes.io/managed-by: Helm
annotations:
spec:
affinity:
podAffinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: memcached
app.kubernetes.io/instance: gitea
topologyKey: kubernetes.io/hostname
weight: 1
nodeAffinity:
securityContext:
fsGroup: 1001
serviceAccountName: default
containers:
- name: memcached
image: docker.io/bitnami/memcached:1.6.19-debian-11-r7
imagePullPolicy: "IfNotPresent"
securityContext:
runAsNonRoot: true
runAsUser: 1001
env:
- name: BITNAMI_DEBUG
value: "false"
- name: MEMCACHED_PORT_NUMBER
value: "11211"
ports:
- name: memcache
containerPort: 11211
livenessProbe:
failureThreshold: 6
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
tcpSocket:
port: memcache
readinessProbe:
failureThreshold: 6
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 3
tcpSocket:
port: memcache
resources:
limits: {}
requests:
cpu: 250m
memory: 256Mi
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}

View File

@@ -0,0 +1,247 @@
# Source: gitea/templates/gitea/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: gitea
annotations:
labels:
helm.sh/chart: gitea-8.3.0
app: gitea
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
app.kubernetes.io/version: "1.19.3"
version: "1.19.3"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
serviceName: gitea
template:
metadata:
annotations:
checksum/config: 27af0e4460a4b6fa0279e60d04c3d82609060dda7af59dd2051139acc1cdb203
checksum/ldap_0: 9356e28431e375c7fc7d624460a9f41c243f14c3f9765c40aa2b13cf46203eaf
labels:
helm.sh/chart: gitea-8.3.0
app: gitea
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
app.kubernetes.io/version: "1.19.3"
version: "1.19.3"
app.kubernetes.io/managed-by: Helm
spec:
securityContext:
fsGroup: 1000
initContainers:
- name: init-directories
image: "gitea/gitea:1.19.3"
imagePullPolicy: Always
command: ["/usr/sbin/init_directory_structure.sh"]
env:
- name: GITEA_APP_INI
value: /data/gitea/conf/app.ini
- name: GITEA_CUSTOM
value: /data/gitea
- name: GITEA_WORK_DIR
value: /data
- name: GITEA_TEMP
value: /tmp/gitea
- name: TZ
value: Europe/Paris
volumeMounts:
- name: init
mountPath: /usr/sbin
- name: temp
mountPath: /tmp
- name: data
mountPath: /data
securityContext:
capabilities:
add:
- SYS_CHROOT
resources:
limits: {}
requests:
cpu: 100m
memory: 128Mi
- name: init-app-ini
image: "gitea/gitea:1.19.3"
imagePullPolicy: Always
command: ["/usr/sbin/config_environment.sh"]
env:
- name: GITEA_APP_INI
value: /data/gitea/conf/app.ini
- name: GITEA_CUSTOM
value: /data/gitea
- name: GITEA_WORK_DIR
value: /data
- name: GITEA_TEMP
value: /tmp/gitea
- name: TZ
value: Europe/Paris
- name: ENV_TO_INI__DATABASE__LOG_SQL
value: "false"
- name: ENV_TO_INI__LOG__LEVEL
value: Debug
volumeMounts:
- name: config
mountPath: /usr/sbin
- name: temp
mountPath: /tmp
- name: data
mountPath: /data
- name: inline-config-sources
mountPath: /env-to-ini-mounts/inlines/
securityContext:
capabilities:
add:
- SYS_CHROOT
resources:
limits: {}
requests:
cpu: 100m
memory: 128Mi
- name: configure-gitea
image: "gitea/gitea:1.19.3"
command: ["/usr/sbin/configure_gitea.sh"]
imagePullPolicy: Always
securityContext:
capabilities:
add:
- SYS_CHROOT
runAsUser: 1000
env:
- name: GITEA_APP_INI
value: /data/gitea/conf/app.ini
- name: GITEA_CUSTOM
value: /data/gitea
- name: GITEA_WORK_DIR
value: /data
- name: GITEA_TEMP
value: /tmp/gitea
- name: GITEA_LDAP_BIND_DN_0
valueFrom:
secretKeyRef:
key: bindDn
name: gitea-ldap
- name: GITEA_LDAP_PASSWORD_0
valueFrom:
secretKeyRef:
key: bindPassword
name: gitea-ldap
- name: GITEA_ADMIN_USERNAME
valueFrom:
secretKeyRef:
key: username
name: gitea-admin-user
- name: GITEA_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: gitea-admin-user
- name: TZ
value: Europe/Paris
volumeMounts:
- name: init
mountPath: /usr/sbin
- name: temp
mountPath: /tmp
- name: data
mountPath: /data
resources:
limits: {}
requests:
cpu: 100m
memory: 128Mi
terminationGracePeriodSeconds: 60
containers:
- name: gitea
image: "gitea/gitea:1.19.3"
imagePullPolicy: Always
env:
# SSH Port values have to be set here as well for openssh configuration
- name: SSH_LISTEN_PORT
value: "2222"
- name: SSH_PORT
value: "2222"
- name: SSH_LOG_LEVEL
value: "INFO"
- name: GITEA_APP_INI
value: /data/gitea/conf/app.ini
- name: GITEA_CUSTOM
value: /data/gitea
- name: GITEA_WORK_DIR
value: /data
- name: GITEA_TEMP
value: /tmp/gitea
- name: TMPDIR
value: /tmp/gitea
- name: TZ
value: Europe/Paris
ports:
- name: ssh
containerPort: 2222
- name: http
containerPort: 3000
livenessProbe:
failureThreshold: 10
initialDelaySeconds: 200
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: http
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: http
timeoutSeconds: 1
resources:
{}
securityContext:
capabilities:
add:
- SYS_CHROOT
volumeMounts:
- name: temp
mountPath: /tmp
- name: data
mountPath: /data
- mountPath: /data/gitea/public/css
name: gitea-themes
volumes:
- name: init
secret:
secretName: gitea-init
defaultMode: 110
- name: config
secret:
secretName: gitea
defaultMode: 110
- configMap:
name: gitea-themes
name: gitea-themes
- name: inline-config-sources
secret:
secretName: gitea-inline-config
- name: temp
emptyDir: {}
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: "10Gi"

136
apps/gitea/datas.tf Normal file
View File

@@ -0,0 +1,136 @@
locals {
common-labels = {
"vynil.solidite.fr/owner-name" = var.instance
"vynil.solidite.fr/owner-namespace" = var.namespace
"vynil.solidite.fr/owner-category" = var.category
"vynil.solidite.fr/owner-component" = var.component
"app.kubernetes.io/managed-by" = "vynil"
"app.kubernetes.io/instance" = var.instance
}
removePatch = <<-EOF
- op: remove
path: /spec/loadBalancerIP
EOF
modifyPatch = <<-EOF
- op: replace
path: /spec/loadBalancerIP
value: "${var.load-balancer.ip}"
EOF
}
data "kubernetes_secret_v1" "postgresql_password" {
depends_on = [kubectl_manifest.gitea_postgresql]
metadata {
name = "${var.component}.${var.instance}-${var.component}.credentials.postgresql.acid.zalan.do"
namespace = var.namespace
}
}
data "kubernetes_secret_v1" "authentik" {
metadata {
name = "authentik"
namespace = "${var.domain}-auth"
}
}
data "kustomization_overlay" "data" {
common_labels = local.common-labels
namespace = var.namespace
resources = [for file in fileset(path.module, "*.yaml"): file if ! contains(["index.yaml", "v1_ConfigMap_gitea-themes.yaml"], file)]
images {
name = "docker.io/bitnami/memcached"
new_name = "${var.images.memcached.registry}/${var.images.memcached.repository}"
new_tag = "${var.images.memcached.tag}"
}
patches {
target {
kind = "StatefulSet"
name = "gitea"
}
patch = <<-EOF
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: gitea
spec:
replicas: ${var.replicas}
template:
spec:
initContainers:
- name: init-directories
image: "${var.images.gitea.registry}/${var.images.gitea.repository}:${var.images.gitea.tag}"
imagePullPolicy: "${var.images.gitea.pullPolicy}"
- name: init-app-ini
image: "${var.images.gitea.registry}/${var.images.gitea.repository}:${var.images.gitea.tag}"
imagePullPolicy: IfNotPresent
- name: configure-gitea
image: "${var.images.gitea.registry}/${var.images.gitea.repository}:${var.images.gitea.tag}"
imagePullPolicy: IfNotPresent
env:
- name: LDAP_USER_SEARCH_BASE
valueFrom:
secretKeyRef:
key: user-search-base
name: gitea-ldap
- name: LDAP_USER_FILTER
valueFrom:
secretKeyRef:
key: user-filter
name: gitea-ldap
- name: LDAP_ADMIN_FILTER
valueFrom:
secretKeyRef:
key: admin-filter
name: gitea-ldap
- name: LDAP_HOST
valueFrom:
secretKeyRef:
key: endpoint
name: gitea-ldap
- name: TZ
value: ${var.timezone}
containers:
- name: gitea
image: "${var.images.gitea.registry}/${var.images.gitea.repository}:${var.images.gitea.tag}"
imagePullPolicy: IfNotPresent
env:
- name: SSH_LISTEN_PORT
value: "2222"
- name: SSH_PORT
value: "${var.ssh-port}"
- name: SSH_LOG_LEVEL
value: "INFO"
- name: TZ
value: ${var.timezone}
volumeClaimTemplates:
- metadata:
name: data
annotations:
k8up.io/backup: "true"
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: "${var.volume.size}"
EOF
}
patches {
target {
kind = "Service"
name = "gitea-ssh"
}
patch = <<-EOF
- op: replace
path: /spec/ports/0/port
value: ${var.ssh-port}
EOF
}
patches {
target {
kind = "Service"
name = "gitea-ssh"
}
patch = var.load-balancer.ip==""?local.removePatch:local.modifyPatch
}
}

18
apps/gitea/index.rhai Normal file
View File

@@ -0,0 +1,18 @@
const NS=config.namespace;
const SRC=src;
const DEST=dest;
fn pre_pack() {
shell("helm repo add gitea-charts https://dl.gitea.io/charts/");
shell(`helm template gitea gitea-charts/gitea --namespace=vynil-ci --values values.yml >${global::SRC}/chart.yaml`);
}
fn post_pack() {
shell(`rm -f ${global::DEST}/v1_Pod_gitea-test-connection.yaml`);
shell(`rm -f ${global::DEST}/v1_Secret_gitea-inline-config.yaml`);
let regex = "'\\\\\\${\\(LDAP_[A-Z_]*\\)}'";
let final = "\\\"\\${\\1}\\\"";
shell(`sed -i "s/${regex}/${final}/g" ${global::DEST}/v1_Secret_gitea-init.yaml`);
}
fn pre_install() {
shell(`kubectl create -n ${global::NS} -f ${global::SRC}/v1_ConfigMap_gitea-themes.yaml || :`);
}

241
apps/gitea/index.yaml Normal file
View File

@@ -0,0 +1,241 @@
---
apiVersion: vinyl.solidite.fr/v1beta1
kind: Component
category: apps
metadata:
name: gitea
description: |-
Git with a cup of tea
A painless self-hosted Git service.
Gitea is a community managed lightweight code hosting solution written in Go. It is published under the MIT license.
options:
images:
default:
gitea:
pullPolicy: IfNotPresent
registry: docker.io
repository: gitea/gitea
tag: 1.19.3
memcached:
registry: docker.io
repository: bitnami/memcached
tag: 1.6.19-debian-11-r7
examples:
- gitea:
pullPolicy: IfNotPresent
registry: docker.io
repository: gitea/gitea
tag: 1.19.3
memcached:
registry: docker.io
repository: bitnami/memcached
tag: 1.6.19-debian-11-r7
properties:
gitea:
default:
pullPolicy: IfNotPresent
registry: docker.io
repository: gitea/gitea
tag: 1.19.3
properties:
pullPolicy:
default: IfNotPresent
enum:
- Always
- Never
- IfNotPresent
type: string
registry:
default: docker.io
type: string
repository:
default: gitea/gitea
type: string
tag:
default: 1.19.3
type: string
type: object
memcached:
default:
registry: docker.io
repository: bitnami/memcached
tag: 1.6.19-debian-11-r7
properties:
registry:
default: docker.io
type: string
repository:
default: bitnami/memcached
type: string
tag:
default: 1.6.19-debian-11-r7
type: string
type: object
type: object
load-balancer:
default:
ip: ''
examples:
- ip: ''
properties:
ip:
default: ''
type: string
type: object
webhook:
default:
allowed-hosts: private
skip-tls-verify: false
examples:
- allowed-hosts: private
skip-tls-verify: false
properties:
allowed-hosts:
default: private
type: string
skip-tls-verify:
default: false
type: boolean
type: object
release:
default: 8.3.0
examples:
- 8.3.0
type: string
push-create:
default:
org: 'true'
private: 'false'
user: 'true'
examples:
- org: 'true'
private: 'false'
user: 'true'
properties:
org:
default: 'true'
type: string
private:
default: 'false'
type: string
user:
default: 'true'
type: string
type: object
volume:
default:
size: 10Gi
examples:
- size: 10Gi
properties:
size:
default: 10Gi
type: string
type: object
default-branch:
default: main
examples:
- main
type: string
postgres:
default:
replicas: 1
storage: 10Gi
version: '14'
examples:
- replicas: 1
storage: 10Gi
version: '14'
properties:
replicas:
default: 1
type: integer
storage:
default: 10Gi
type: string
version:
default: '14'
type: string
type: object
ingress-class:
default: traefik
examples:
- traefik
type: string
ssh-port:
default: 2222
examples:
- 2222
type: integer
domain-name:
default: your_company.com
examples:
- your_company.com
type: string
domain:
default: your-company
examples:
- your-company
type: string
issuer:
default: letsencrypt-prod
examples:
- letsencrypt-prod
type: string
disable-registration:
default: true
examples:
- true
type: boolean
replicas:
default: 1
examples:
- 1
type: integer
sub-domain:
default: git
examples:
- git
type: string
admin:
default:
email: git-admin@git.your_company.com
name: gitea_admin
examples:
- email: git-admin@git.your_company.com
name: gitea_admin
properties:
email:
default: git-admin@git.your_company.com
type: string
name:
default: gitea_admin
type: string
type: object
timezone:
default: Europe/Paris
examples:
- Europe/Paris
type: string
theme:
default: gitea-modern
examples:
- gitea-modern
type: string
dependencies:
- dist: null
category: share
component: authentik-ldap
- dist: null
category: core
component: secret-generator
- dist: null
category: dbo
component: postgresql
providers:
kubernetes: true
authentik: true
kubectl: true
postgresql: null
restapi: true
http: true

69
apps/gitea/ingress.tf Normal file
View File

@@ -0,0 +1,69 @@
locals {
dns-names = ["${var.sub-domain}.${var.domain-name}"]
middlewares = [{"name" = "${var.instance}-https"}]
services = [{
"kind" = "Service"
"name" = "gitea-http"
"namespace" = var.namespace
"port" = 3000
}]
routes = [ for v in local.dns-names : {
"kind" = "Rule"
"match" = "Host(`${v}`)"
"middlewares" = local.middlewares
"services" = local.services
}]
}
resource "kubectl_manifest" "gitea_certificate" {
yaml_body = <<-EOF
apiVersion: "cert-manager.io/v1"
kind: "Certificate"
metadata:
name: "${var.instance}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
secretName: "${var.instance}-cert"
dnsNames: ${jsonencode(local.dns-names)}
issuerRef:
name: "${var.issuer}"
kind: "ClusterIssuer"
group: "cert-manager.io"
EOF
}
resource "kubectl_manifest" "gitea_https_redirect" {
yaml_body = <<-EOF
apiVersion: "traefik.containo.us/v1alpha1"
kind: "Middleware"
metadata:
name: "${var.instance}-https"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
redirectScheme:
scheme: "https"
permanent: true
EOF
}
resource "kubectl_manifest" "gitea_ingress" {
force_conflicts = true
yaml_body = <<-EOF
apiVersion: "traefik.containo.us/v1alpha1"
kind: "IngressRoute"
metadata:
name: "${var.instance}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
# annotations:
# "kubernetes.io/ingress.class": "${var.ingress-class}"
spec:
entryPoints: ["web","websecure"]
routes: ${jsonencode(local.routes)}
tls:
secretName: "${var.instance}-cert"
EOF
}

View File

@@ -0,0 +1,54 @@
resource "kubernetes_secret_v1" "gitea_inline_config" {
metadata {
name = "gitea-inline-config"
namespace = var.namespace
labels = local.common-labels
}
data = {
"_generals_" = ""
metrics = "ENABLED=true"
security = "INSTALL_LOCK=true"
service = "DISABLE_REGISTRATION=${var.disable-registration}"
cache = <<-EOF
ADAPTER=memcache
ENABLED=true
HOST=gitea-memcached.${var.namespace}.svc:11211
EOF
database = <<-EOF
DB_TYPE=postgres
HOST=${var.instance}-${var.component}.${var.namespace}.svc:5432
NAME=${var.component}
PASSWD=${data.kubernetes_secret_v1.postgresql_password.data["password"]}
USER=${data.kubernetes_secret_v1.postgresql_password.data["username"]}
SSL_MODE=require
EOF
repository = <<-EOF
DEFAULT_BRANCH=${var.default-branch}
DEFAULT_PUSH_CREATE_PRIVATE=${var.push-create.private}
ENABLE_PUSH_CREATE_ORG=${var.push-create.org}
ENABLE_PUSH_CREATE_USER=${var.push-create.user}
ROOT=/data/git/gitea-repositories
EOF
server = <<-EOF
APP_DATA_PATH=/data
DOMAIN=${var.sub-domain}.${var.domain-name}
ENABLE_PPROF=false
HTTP_PORT=3000
PROTOCOL=http
ROOT_URL=https://${var.sub-domain}.${var.domain-name}
SSH_DOMAIN=${var.sub-domain}.${var.domain-name}
SSH_LISTEN_PORT=${var.ssh-port}
SSH_PORT=${var.ssh-port}
EOF
ui = <<-EOF
DEFAULT_THEME=${var.theme}
SHOW_USER_EMAIL=false
THEMES=auto,gitea,arc-green,edge-auto,edge-dark,edge-light,everforest-auto,everforest-dark,everforest-light,gitea-modern,gruvbox-auto,gruvbox-dark,gruvbox-light,gruvbox-material-auto,gruvbox-material-dark,gruvbox-material-light,palenight,soft-era,sonokai-andromeda,sonokai-atlantis,sonokai-espresso,sonokai-maia,sonokai-shusia,sonokai,theme-nord
EOF
webhook = <<-EOF
ALLOWED_HOST_LIST=${var.webhook.allowed-hosts}
SKIP_TLS_VERIFY=${var.webhook.skip-tls-verify}
EOF
}
}

149
apps/gitea/ldap.tf Normal file
View File

@@ -0,0 +1,149 @@
locals {
base-dn = format("dc=%s", join(",dc=", split(".", format("%s.%s", var.sub-domain, var.domain-name))))
base-group-dn = format("ou=groups,%s", local.base-dn)
base-user-dn = format("ou=users,%s", local.base-dn)
authentik-token = data.kubernetes_secret_v1.authentik.data["AUTHENTIK_BOOTSTRAP_TOKEN"]
request_headers = {
"Content-Type" = "application/json"
Authorization = "Bearer ${local.authentik-token}"
}
ldap-outpost-prividers = jsondecode(data.http.get_ldap_outpost.response_body).results[0].providers
ldap-outpost-pk = jsondecode(data.http.get_ldap_outpost.response_body).results[0].pk
}
resource "kubectl_manifest" "gitea_ldap" {
ignore_fields = ["metadata.annotations"]
yaml_body = <<-EOF
apiVersion: "secretgenerator.mittwald.de/v1alpha1"
kind: "StringSecret"
metadata:
name: "${var.component}-ldap"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
forceRegenerate: false
data:
bindDn: "cn=${var.component}-ldapsearch,${local.base-user-dn}"
user-search-base: "${local.base-user-dn}"
user-filter: "(&(|(memberof=cn=gitea_admin,${local.base-group-dn})(memberof=cn=gitea_users,${local.base-group-dn}))(|(cn=%[1]s)(mail=%[1]s)))"
admin-filter: "(memberof=cn=gitea_admin,${local.base-group-dn})"
endpoint: "ak-outpost-ldap.${var.domain}-auth.svc"
fields:
- fieldName: "bindPassword"
length: "32"
EOF
}
data "kubernetes_secret_v1" "gitea_ldap_password" {
depends_on = [kubectl_manifest.gitea_ldap]
metadata {
name = kubectl_manifest.gitea_ldap.name
namespace = var.namespace
}
}
resource "authentik_user" "gitea_ldapsearch" {
username = "${var.component}-ldapsearch"
name = "${var.component}-ldapsearch"
}
resource "authentik_group" "gitea_ldapsearch" {
name = "${var.component}-ldapsearch"
users = [authentik_user.gitea_ldapsearch.id]
is_superuser = true
}
data "http" "gitea_ldapsearch_password" {
url = "http://authentik.${var.domain}-auth.svc/api/v3/core/users/${authentik_user.gitea_ldapsearch.id}/set_password/"
method = "POST"
request_headers = local.request_headers
request_body = jsonencode({password=data.kubernetes_secret_v1.gitea_ldap_password.data["bindPassword"]})
lifecycle {
postcondition {
condition = contains([201, 204], self.status_code)
error_message = "Status code invalid"
}
}
}
data "authentik_flow" "ldap-authentication-flow" {
depends_on = [authentik_user.gitea_ldapsearch] # fake dependency so it is not evaluated at plan stage
slug = "ldap-authentication-flow"
}
resource "authentik_provider_ldap" "gitea_provider_ldap" {
name = "gitea-ldap-provider"
base_dn = local.base-dn
search_group = authentik_group.gitea_ldapsearch.id
bind_flow = data.authentik_flow.ldap-authentication-flow.id
}
resource "authentik_application" "gitea_application" {
name = "gitea"
slug = "gitea"
protocol_provider = authentik_provider_ldap.gitea_provider_ldap.id
meta_launch_url = format("https://%s.%s", var.sub-domain, var.domain-name)
meta_icon = format("https://%s.%s/%s", var.sub-domain, var.domain-name, "assets/img/logo.svg")
}
resource "authentik_group" "gitea_users" {
name = "gitea_users"
}
data "authentik_group" "vynil-admin" {
depends_on = [authentik_group.gitea_users] # fake dependency so it is not evaluated at plan stage
name = "vynil-ldap-admins"
}
resource "authentik_group" "gitea_admin" {
name = "gitea_admin"
parent = authentik_group.gitea_users.id
}
resource "authentik_policy_binding" "gitea_access_users" {
target = authentik_application.gitea_application.uuid
group = authentik_group.gitea_users.id
order = 0
}
resource "authentik_policy_binding" "gitea_access_vynil" {
target = authentik_application.gitea_application.uuid
group = data.authentik_group.vynil-admin.id
order = 1
}
resource "authentik_policy_binding" "gitea_access_ldap" {
target = authentik_application.gitea_application.uuid
group = authentik_group.gitea_ldapsearch.id
order = 2
}
data "http" "get_ldap_outpost" {
depends_on = [authentik_group.gitea_users] # fake dependency so it is not evaluated at plan stage
url = "http://authentik.${var.domain}-auth.svc/api/v3/outposts/instances/?name__iexact=ldap"
method = "GET"
request_headers = local.request_headers
lifecycle {
postcondition {
condition = contains([200], self.status_code)
error_message = "Status code invalid"
}
}
}
provider "restapi" {
uri = "http://authentik.${var.domain}-auth.svc/api/v3/"
headers = local.request_headers
create_method = "PATCH"
update_method = "PATCH"
destroy_method = "PATCH"
write_returns_object = true
id_attribute = "name"
}
resource "restapi_object" "ldap_outpost_binding" {
path = "/outposts/instances/${local.ldap-outpost-pk}/"
data = jsonencode({
name = "ldap"
providers = contains(local.ldap-outpost-prividers, authentik_provider_ldap.gitea_provider_ldap.id) ? local.ldap-outpost-prividers : concat(local.ldap-outpost-prividers, [authentik_provider_ldap.gitea_provider_ldap.id])
})
}

31
apps/gitea/postgresql.tf Normal file
View File

@@ -0,0 +1,31 @@
locals {
pg-labels = merge(local.common-labels, {
"app.kubernetes.io/component" = "postgresql"
})
}
resource "kubectl_manifest" "gitea_postgresql" {
yaml_body = <<-EOF
apiVersion: "acid.zalan.do/v1"
kind: "postgresql"
metadata:
name: "${var.instance}-${var.component}"
namespace: "${var.namespace}"
labels: ${jsonencode(local.pg-labels)}
spec:
databases:
${var.component}: "${var.component}"
numberOfInstances: ${var.postgres.replicas}
podAnnotations:
"k8up.io/backupcommand": "pg_dump -U postgres -d ${var.component} --clean"
"k8up.io/file-extension": ".sql"
postgresql:
version: "${var.postgres.version}"
teamId: "${var.instance}"
users:
${var.component}:
- "superuser"
- "createdb"
volume:
size: "${var.postgres.storage}"
EOF
}

19
apps/gitea/secret.tf Normal file
View File

@@ -0,0 +1,19 @@
resource "kubectl_manifest" "gitea_secret" {
ignore_fields = ["metadata.annotations"]
yaml_body = <<-EOF
apiVersion: "secretgenerator.mittwald.de/v1alpha1"
kind: "StringSecret"
metadata:
name: "gitea-admin-user"
namespace: "${var.namespace}"
labels: ${jsonencode(local.common-labels)}
spec:
forceRegenerate: false
data:
username: "${var.admin.name}"
fields:
- fieldName: "password"
length: "32"
EOF
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
# Source: gitea/templates/gitea/init.yaml
apiVersion: v1
kind: Secret
metadata:
name: gitea-init
labels:
helm.sh/chart: gitea-8.3.0
app: gitea
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
app.kubernetes.io/version: "1.19.3"
version: "1.19.3"
app.kubernetes.io/managed-by: Helm
type: Opaque
stringData:
configure_gpg_environment.sh: |-
#!/usr/bin/env bash
set -eu
gpg --batch --import /raw/private.asc
init_directory_structure.sh: |-
#!/usr/bin/env bash
set -euo pipefail
set -x
chown 1000:1000 /data
mkdir -p /data/git/.ssh
chmod -R 700 /data/git/.ssh
[ ! -d /data/gitea/conf ] && mkdir -p /data/gitea/conf
# prepare temp directory structure
mkdir -p "${GITEA_TEMP}"
chown 1000:1000 "${GITEA_TEMP}"
chmod ug+rwx "${GITEA_TEMP}"
configure_gitea.sh: |-
#!/usr/bin/env bash
set -euo pipefail
echo '==== BEGIN GITEA CONFIGURATION ===='
{ # try
gitea migrate
} || { # catch
echo "Gitea migrate might fail due to database connection...This init-container will try again in a few seconds"
exit 1
}
function configure_admin_user() {
local ACCOUNT_ID=$(gitea admin user list --admin | grep -e "\s\+${GITEA_ADMIN_USERNAME}\s\+" | awk -F " " "{printf \$1}")
if [[ -z "${ACCOUNT_ID}" ]]; then
echo "No admin user '${GITEA_ADMIN_USERNAME}' found. Creating now..."
gitea admin user create --admin --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --email "git-admin@local.com" --must-change-password=false
echo '...created.'
else
echo "Admin account '${GITEA_ADMIN_USERNAME}' already exist. Running update to sync password..."
gitea admin user change-password --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}"
echo '...password sync done.'
fi
}
configure_admin_user
function configure_ldap() {
local LDAP_NAME='Authentik'
local GITEA_AUTH_ID=$(gitea admin auth list --vertical-bars | grep -E "\|${LDAP_NAME}\s+\|" | grep -iE '\|LDAP \(via BindDN\)\s+\|' | awk -F " " "{print \$1}")
if [[ -z "${GITEA_AUTH_ID}" ]]; then
echo "No ldap configuration found with name "${LDAP_NAME}". Installing it now..."
gitea admin auth add-ldap --admin-filter "${LDAP_ADMIN_FILTER}" --avatar-attribute 'jpegPhoto' --bind-dn "${GITEA_LDAP_BIND_DN_0}" --bind-password "${GITEA_LDAP_PASSWORD_0}" --email-attribute 'mail' --firstname-attribute 'givenname' --host "${LDAP_HOST}" --name 'Authentik' --port 389 --security-protocol 'unencrypted' --surname-attribute 'name' --user-filter "${LDAP_USER_FILTER}" --user-search-base "${LDAP_USER_SEARCH_BASE}" --username-attribute 'cn'
echo '...installed.'
else
echo "Existing ldap configuration with name "${LDAP_NAME}": '${GITEA_AUTH_ID}'. Running update to sync settings..."
gitea admin auth update-ldap --id "${GITEA_AUTH_ID}" --admin-filter "${LDAP_ADMIN_FILTER}" --avatar-attribute 'jpegPhoto' --bind-dn "${GITEA_LDAP_BIND_DN_0}" --bind-password "${GITEA_LDAP_PASSWORD_0}" --email-attribute 'mail' --firstname-attribute 'givenname' --host "${LDAP_HOST}" --name 'Authentik' --port 389 --security-protocol 'unencrypted' --surname-attribute 'name' --user-filter "${LDAP_USER_FILTER}" --user-search-base "${LDAP_USER_SEARCH_BASE}" --username-attribute 'cn'
echo '...sync settings done.'
fi
}
configure_ldap
function configure_oauth() {
echo 'no oauth configuration... skipping.'
}
configure_oauth
echo '==== END GITEA CONFIGURATION ===='

View File

@@ -0,0 +1,169 @@
# Source: gitea/templates/gitea/config.yaml
apiVersion: v1
kind: Secret
metadata:
name: gitea
labels:
helm.sh/chart: gitea-8.3.0
app: gitea
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
app.kubernetes.io/version: "1.19.3"
version: "1.19.3"
app.kubernetes.io/managed-by: Helm
type: Opaque
stringData:
config_environment.sh: |-
#!/usr/bin/env bash
set -euo pipefail
function env2ini::log() {
printf "${1}\n"
}
function env2ini::read_config_to_env() {
local section="${1}"
local line="${2}"
if [[ -z "${line}" ]]; then
# skip empty line
return
fi
# 'xargs echo -n' trims all leading/trailing whitespaces and a trailing new line
local setting="$(awk -F '=' '{print $1}' <<< "${line}" | xargs echo -n)"
if [[ -z "${setting}" ]]; then
env2ini::log ' ! invalid setting'
exit 1
fi
local value=''
local regex="^${setting}(\s*)=(\s*)(.*)"
if [[ $line =~ $regex ]]; then
value="${BASH_REMATCH[3]}"
else
env2ini::log ' ! invalid setting'
exit 1
fi
env2ini::log " + '${setting}'"
if [[ -z "${section}" ]]; then
export "ENV_TO_INI____${setting^^}=${value}" # '^^' makes the variable content uppercase
return
fi
local masked_section="${section//./_0X2E_}" # '//' instructs to replace all matches
masked_section="${masked_section//-/_0X2D_}"
export "ENV_TO_INI__${masked_section^^}__${setting^^}=${value}" # '^^' makes the variable content uppercase
}
function env2ini::reload_preset_envs() {
env2ini::log "Reloading preset envs..."
while read -r line; do
if [[ -z "${line}" ]]; then
# skip empty line
return
fi
# 'xargs echo -n' trims all leading/trailing whitespaces and a trailing new line
local setting="$(awk -F '=' '{print $1}' <<< "${line}" | xargs echo -n)"
if [[ -z "${setting}" ]]; then
env2ini::log ' ! invalid setting'
exit 1
fi
local value=''
local regex="^${setting}(\s*)=(\s*)(.*)"
if [[ $line =~ $regex ]]; then
value="${BASH_REMATCH[3]}"
else
env2ini::log ' ! invalid setting'
exit 1
fi
env2ini::log " + '${setting}'"
export "${setting^^}=${value}" # '^^' makes the variable content uppercase
done < "/tmp/existing-envs"
rm /tmp/existing-envs
}
function env2ini::process_config_file() {
local config_file="${1}"
local section="$(basename "${config_file}")"
if [[ $section == '_generals_' ]]; then
env2ini::log " [ini root]"
section=''
else
env2ini::log " ${section}"
fi
while read -r line; do
env2ini::read_config_to_env "${section}" "${line}"
done < <(awk 1 "${config_file}") # Helm .toYaml trims the trailing new line which breaks line processing; awk 1 ... adds it back while reading
}
function env2ini::load_config_sources() {
local path="${1}"
if [[ -d "${path}" ]]; then
env2ini::log "Processing $(basename "${path}")..."
while read -d '' configFile; do
env2ini::process_config_file "${configFile}"
done < <(find "${path}" -type l -not -name '..data' -print0)
env2ini::log "\n"
fi
}
function env2ini::generate_initial_secrets() {
# These environment variables will either be
# - overwritten with user defined values,
# - initially used to set up Gitea
# Anyway, they won't harm existing app.ini files
export ENV_TO_INI__SECURITY__INTERNAL_TOKEN=$(gitea generate secret INTERNAL_TOKEN)
export ENV_TO_INI__SECURITY__SECRET_KEY=$(gitea generate secret SECRET_KEY)
export ENV_TO_INI__OAUTH2__JWT_SECRET=$(gitea generate secret JWT_SECRET)
export ENV_TO_INI__SERVER__LFS_JWT_SECRET=$(gitea generate secret LFS_JWT_SECRET)
env2ini::log "...Initial secrets generated\n"
}
env | (grep ENV_TO_INI || [[ $? == 1 ]]) > /tmp/existing-envs
# MUST BE CALLED BEFORE OTHER CONFIGURATION
env2ini::generate_initial_secrets
env2ini::load_config_sources '/env-to-ini-mounts/inlines/'
env2ini::load_config_sources '/env-to-ini-mounts/additionals/'
# load existing envs to override auto generated envs
env2ini::reload_preset_envs
env2ini::log "=== All configuration sources loaded ===\n"
# safety to prevent rewrite of secret keys if an app.ini already exists
if [ -f ${GITEA_APP_INI} ]; then
env2ini::log 'An app.ini file already exists. To prevent overwriting secret keys, these settings are dropped and remain unchanged:'
env2ini::log ' - security.INTERNAL_TOKEN'
env2ini::log ' - security.SECRET_KEY'
env2ini::log ' - oauth2.JWT_SECRET'
env2ini::log ' - server.LFS_JWT_SECRET'
unset ENV_TO_INI__SECURITY__INTERNAL_TOKEN
unset ENV_TO_INI__SECURITY__SECRET_KEY
unset ENV_TO_INI__OAUTH2__JWT_SECRET
unset ENV_TO_INI__SERVER__LFS_JWT_SECRET
fi
environment-to-ini -o $GITEA_APP_INI -p ENV_TO_INI

View File

@@ -0,0 +1,25 @@
# Source: gitea/templates/gitea/http-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: gitea-http
labels:
helm.sh/chart: gitea-8.3.0
app: gitea
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
app.kubernetes.io/version: "1.19.3"
version: "1.19.3"
app.kubernetes.io/managed-by: Helm
annotations:
{}
spec:
type: ClusterIP
clusterIP: None
ports:
- name: http
port: 3000
targetPort: 3000
selector:
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea

View File

@@ -0,0 +1,23 @@
# Source: gitea/charts/memcached/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: gitea-memcached
namespace: vynil-ci
labels:
app.kubernetes.io/name: memcached
helm.sh/chart: memcached-6.3.14
app.kubernetes.io/instance: gitea
app.kubernetes.io/managed-by: Helm
annotations:
spec:
type: ClusterIP
sessionAffinity: None
ports:
- name: memcache
port: 11211
targetPort: memcache
nodePort: null
selector:
app.kubernetes.io/name: memcached
app.kubernetes.io/instance: gitea

View File

@@ -0,0 +1,28 @@
# Source: gitea/templates/gitea/ssh-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: gitea-ssh
labels:
helm.sh/chart: gitea-8.3.0
app: gitea
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea
app.kubernetes.io/version: "1.19.3"
version: "1.19.3"
app.kubernetes.io/managed-by: Helm
annotations:
metallb.universe.tf/address-pool: mlb-pool-public
metallb.universe.tf/allow-shared-ip: traefik-public-ip
spec:
type: LoadBalancer
loadBalancerIP: 1.2.3.4
ipFamilyPolicy: PreferDualStack
ports:
- name: ssh
port: 2222
targetPort: 2222
protocol: TCP
selector:
app.kubernetes.io/name: gitea
app.kubernetes.io/instance: gitea