Add Argo Workflows, mTLS container registry, and fix infrastructure
- Move Keycloak off Helm to plain Crossplane Object manifests (PostgreSQL + Keycloak deployment) - Add Vaultwarden SSO/OIDC config with Keycloak, fix Recreate deployment strategy for RWO volumes - Switch routing from Helm-based Pomerium to pomerium-allinone with all service routes - Deploy Argo Workflows (controller, server, CRDs, RBAC) with KEDA queue-depth autoscaling - Add Civo cluster autoscaler with pool-scaler for zero-to-one scale-up via Civo API - Add node-labeler to auto-tag nodes by pool membership for nodeSelector scheduling - Set up mTLS container registry at registry.nge6.com (Forgejo built-in, client cert required) - Add internal registry route (registry-internal.nge6.com) for in-cluster image pulls - Fix DNS records for new Emissary LB IP (212.2.241.28) - Fix CoreDNS crash from invalid custom config - Fix Emissary apiext expired webhook CA certificate Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0b60e24c4f
commit
0dee133377
21 changed files with 2244 additions and 75 deletions
46
ambassador-listeners.yaml
Normal file
46
ambassador-listeners.yaml
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Ambassador Listeners - required for Ambassador 3.x
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: http-listener
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Listener
|
||||||
|
metadata:
|
||||||
|
name: http-listener
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
port: 8080
|
||||||
|
protocol: HTTP
|
||||||
|
securityModel: XFP
|
||||||
|
hostBinding:
|
||||||
|
namespace:
|
||||||
|
from: ALL
|
||||||
|
---
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: https-listener
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Listener
|
||||||
|
metadata:
|
||||||
|
name: https-listener
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
port: 8443
|
||||||
|
protocol: HTTPS
|
||||||
|
securityModel: XFP
|
||||||
|
hostBinding:
|
||||||
|
namespace:
|
||||||
|
from: ALL
|
||||||
70
argo-workflows/argo-ingress.yaml
Normal file
70
argo-workflows/argo-ingress.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# SSL Certificate for Argo Workflows UI
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-certificate
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: argo-tls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
secretName: argo-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-dns
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- workflows.nge6.com
|
||||||
|
---
|
||||||
|
# Ambassador Host for Argo UI
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-host
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Host
|
||||||
|
metadata:
|
||||||
|
name: argo-host
|
||||||
|
namespace: emissary
|
||||||
|
annotations:
|
||||||
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
|
spec:
|
||||||
|
hostname: workflows.nge6.com
|
||||||
|
tlsSecret:
|
||||||
|
name: argo-tls
|
||||||
|
---
|
||||||
|
# Ambassador Mapping for Argo UI through Pomerium
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-mapping
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Mapping
|
||||||
|
metadata:
|
||||||
|
name: argo-mapping
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
hostname: workflows.nge6.com
|
||||||
|
prefix: /
|
||||||
|
service: http://pomerium-allinone.pomerium:443
|
||||||
|
timeout_ms: 30000
|
||||||
|
connect_timeout_ms: 10000
|
||||||
440
argo-workflows/argo-workflows.yaml
Normal file
440
argo-workflows/argo-workflows.yaml
Normal file
|
|
@ -0,0 +1,440 @@
|
||||||
|
# Argo Workflows namespace
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-namespace
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: argo
|
||||||
|
---
|
||||||
|
# Argo Workflows ServiceAccount
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-sa
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: argo
|
||||||
|
namespace: argo
|
||||||
|
---
|
||||||
|
# Argo Server ServiceAccount
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-server-sa
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: argo-server
|
||||||
|
namespace: argo
|
||||||
|
---
|
||||||
|
# Argo Workflows ClusterRole
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-cluster-role
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: argo-cluster-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [pods, pods/exec, pods/log]
|
||||||
|
verbs: [create, get, list, watch, update, patch, delete]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [configmaps, secrets, services, serviceaccounts, persistentvolumeclaims, events]
|
||||||
|
verbs: [create, get, list, watch, update, patch, delete]
|
||||||
|
- apiGroups: [argoproj.io]
|
||||||
|
resources: [workflows, workflows/finalizers, workflowtemplates, workflowtemplates/finalizers, clusterworkflowtemplates, clusterworkflowtemplates/finalizers, cronworkflows, cronworkflows/finalizers, workfloweventbindings, workfloweventbindings/finalizers, workflowtaskresults, workflowartifactgctasks]
|
||||||
|
verbs: [create, get, list, watch, update, patch, delete]
|
||||||
|
- apiGroups: [argoproj.io]
|
||||||
|
resources: [workflowtasksets, workflowtasksets/status]
|
||||||
|
verbs: [create, get, list, watch, update, patch, delete]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [events]
|
||||||
|
verbs: [create, patch]
|
||||||
|
- apiGroups: [coordination.k8s.io]
|
||||||
|
resources: [leases]
|
||||||
|
verbs: [create, get, update]
|
||||||
|
---
|
||||||
|
# Argo Server ClusterRole
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-server-cluster-role
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: argo-server-cluster-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [configmaps, events]
|
||||||
|
verbs: [get, watch, list]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [pods, pods/exec, pods/log]
|
||||||
|
verbs: [get, list, watch]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [secrets]
|
||||||
|
verbs: [get, list, watch, create]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [events]
|
||||||
|
verbs: [watch, create, patch]
|
||||||
|
- apiGroups: [argoproj.io]
|
||||||
|
resources: [workflows, workflowtemplates, clusterworkflowtemplates, cronworkflows, workfloweventbindings]
|
||||||
|
verbs: [create, get, list, watch, update, patch, delete]
|
||||||
|
- apiGroups: [argoproj.io]
|
||||||
|
resources: [workflowtasksets]
|
||||||
|
verbs: [list, watch]
|
||||||
|
---
|
||||||
|
# Argo ClusterRoleBinding
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-cluster-role-binding
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: argo-binding
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: argo
|
||||||
|
namespace: argo
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: argo-cluster-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
# Argo Server ClusterRoleBinding
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-server-cluster-role-binding
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: argo-server-binding
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: argo-server
|
||||||
|
namespace: argo
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: argo-server-cluster-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
# Default workflow ServiceAccount (used by workflows themselves)
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-sa
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow
|
||||||
|
namespace: argo
|
||||||
|
---
|
||||||
|
# Workflow role - what workflows can do
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-role
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-role
|
||||||
|
namespace: argo
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [pods]
|
||||||
|
verbs: [get, watch, patch]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [pods/log]
|
||||||
|
verbs: [get, watch]
|
||||||
|
- apiGroups: [argoproj.io]
|
||||||
|
resources: [workflowtaskresults]
|
||||||
|
verbs: [create, patch]
|
||||||
|
---
|
||||||
|
# Workflow RoleBinding
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-role-binding
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-binding
|
||||||
|
namespace: argo
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: argo-workflow
|
||||||
|
namespace: argo
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: argo-workflow-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
# Workflow Controller ConfigMap
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-controller-configmap
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: workflow-controller-configmap
|
||||||
|
namespace: argo
|
||||||
|
data:
|
||||||
|
config: |
|
||||||
|
workflowDefaults:
|
||||||
|
spec:
|
||||||
|
serviceAccountName: argo-workflow
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: forgejo-registry
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.civo.com/node-pool: high-compute
|
||||||
|
tolerations:
|
||||||
|
- key: "kubernetes.civo.com/node-pool"
|
||||||
|
operator: "Equal"
|
||||||
|
value: "high-compute"
|
||||||
|
effect: "NoSchedule"
|
||||||
|
metricsConfig:
|
||||||
|
enabled: true
|
||||||
|
path: /metrics
|
||||||
|
port: 9090
|
||||||
|
---
|
||||||
|
# Workflow Controller Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-controller
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: workflow-controller
|
||||||
|
namespace: argo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: workflow-controller
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: workflow-controller
|
||||||
|
spec:
|
||||||
|
serviceAccountName: argo
|
||||||
|
containers:
|
||||||
|
- name: workflow-controller
|
||||||
|
image: quay.io/argoproj/workflow-controller:v3.6.7
|
||||||
|
args:
|
||||||
|
- --configmap
|
||||||
|
- workflow-controller-configmap
|
||||||
|
- --executor-image
|
||||||
|
- quay.io/argoproj/argoexec:v3.6.7
|
||||||
|
- --loglevel
|
||||||
|
- info
|
||||||
|
env:
|
||||||
|
- name: LEADER_ELECTION_IDENTITY
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.name
|
||||||
|
ports:
|
||||||
|
- containerPort: 9090
|
||||||
|
name: metrics
|
||||||
|
- containerPort: 6060
|
||||||
|
name: pprof
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 6060
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 6060
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
---
|
||||||
|
# Workflow Controller Metrics Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-workflow-controller-metrics
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: workflow-controller-metrics
|
||||||
|
namespace: argo
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: workflow-controller
|
||||||
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
port: 9090
|
||||||
|
targetPort: 9090
|
||||||
|
type: ClusterIP
|
||||||
|
---
|
||||||
|
# Argo Server Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-server-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: argo-server
|
||||||
|
namespace: argo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: argo-server
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: argo-server
|
||||||
|
spec:
|
||||||
|
serviceAccountName: argo-server
|
||||||
|
containers:
|
||||||
|
- name: argo-server
|
||||||
|
image: quay.io/argoproj/argocli:v3.6.7
|
||||||
|
args:
|
||||||
|
- server
|
||||||
|
- --auth-mode=server
|
||||||
|
- --secure=false
|
||||||
|
ports:
|
||||||
|
- containerPort: 2746
|
||||||
|
name: web
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 256Mi
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 2746
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
---
|
||||||
|
# Argo Server Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-server-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: argo-server
|
||||||
|
namespace: argo
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: argo-server
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
port: 2746
|
||||||
|
targetPort: 2746
|
||||||
|
type: ClusterIP
|
||||||
78
argo-workflows/keda-autoscaler.yaml
Normal file
78
argo-workflows/keda-autoscaler.yaml
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Placeholder deployment that KEDA scales based on Argo queue depth.
|
||||||
|
# When scaled up, these pods request resources on the high-compute pool,
|
||||||
|
# triggering the Civo cluster autoscaler to add nodes.
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-queue-placeholder
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: argo-queue-placeholder
|
||||||
|
namespace: argo
|
||||||
|
spec:
|
||||||
|
replicas: 0
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: argo-queue-placeholder
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: argo-queue-placeholder
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.civo.com/node-pool: high-compute
|
||||||
|
tolerations:
|
||||||
|
- key: "kubernetes.civo.com/node-pool"
|
||||||
|
operator: "Equal"
|
||||||
|
value: "high-compute"
|
||||||
|
effect: "NoSchedule"
|
||||||
|
terminationGracePeriodSeconds: 0
|
||||||
|
containers:
|
||||||
|
- name: placeholder
|
||||||
|
image: busybox
|
||||||
|
command: ["sleep", "infinity"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
---
|
||||||
|
# KEDA ScaledObject - scales placeholder based on pending Argo workflow pods.
|
||||||
|
# When workflows are submitted, their pods land in Pending state (no nodes).
|
||||||
|
# KEDA sees the pending pods and scales up the placeholder deployment,
|
||||||
|
# which also targets high-compute nodes, adding pressure for the cluster
|
||||||
|
# autoscaler to provision new nodes.
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-queue-scaledobject
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: keda.sh/v1alpha1
|
||||||
|
kind: ScaledObject
|
||||||
|
metadata:
|
||||||
|
name: argo-queue-scaler
|
||||||
|
namespace: argo
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: argo-queue-placeholder
|
||||||
|
pollingInterval: 15
|
||||||
|
cooldownPeriod: 300
|
||||||
|
minReplicaCount: 0
|
||||||
|
maxReplicaCount: 5
|
||||||
|
triggers:
|
||||||
|
- type: kubernetes-workload
|
||||||
|
metadata:
|
||||||
|
podSelector: "workflows.argoproj.io/completed=false"
|
||||||
|
namespace: "argo"
|
||||||
|
value: "1"
|
||||||
|
|
@ -40,6 +40,31 @@ spec:
|
||||||
providerConfigRef:
|
providerConfigRef:
|
||||||
name: keycloak-provider
|
name: keycloak-provider
|
||||||
---
|
---
|
||||||
|
# Vaultwarden OIDC Client
|
||||||
|
apiVersion: openidclient.keycloak.crossplane.io/v1alpha1
|
||||||
|
kind: Client
|
||||||
|
metadata:
|
||||||
|
name: vaultwarden-client
|
||||||
|
spec:
|
||||||
|
forProvider:
|
||||||
|
realmId: kubernetes-realm
|
||||||
|
clientId: vaultwarden
|
||||||
|
name: "Vaultwarden Password Manager"
|
||||||
|
description: "Client for Vaultwarden OIDC authentication"
|
||||||
|
enabled: true
|
||||||
|
accessType: CONFIDENTIAL
|
||||||
|
clientAuthenticatorType: client-secret
|
||||||
|
validRedirectUris:
|
||||||
|
- "https://vault.nge6.com/identity/connect/oidc-signin"
|
||||||
|
- "https://vault.nge6.com/sso-connector/oidc/callback"
|
||||||
|
standardFlowEnabled: true
|
||||||
|
directAccessGrantsEnabled: false
|
||||||
|
serviceAccountsEnabled: false
|
||||||
|
webOrigins:
|
||||||
|
- "https://vault.nge6.com"
|
||||||
|
providerConfigRef:
|
||||||
|
name: keycloak-provider
|
||||||
|
---
|
||||||
# Create user groups
|
# Create user groups
|
||||||
apiVersion: group.keycloak.crossplane.io/v1alpha1
|
apiVersion: group.keycloak.crossplane.io/v1alpha1
|
||||||
kind: Group
|
kind: Group
|
||||||
|
|
@ -190,7 +215,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
forProvider:
|
forProvider:
|
||||||
realmId: kubernetes-realm
|
realmId: kubernetes-realm
|
||||||
groupId: k8s-admins
|
groupId: 98e13ab3-0001-4646-b097-ed52ee5baff4
|
||||||
members: ["admin", "eemoore"]
|
members: ["admin", "eemoore"]
|
||||||
providerConfigRef:
|
providerConfigRef:
|
||||||
name: keycloak-provider
|
name: keycloak-provider
|
||||||
|
|
@ -202,7 +227,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
forProvider:
|
forProvider:
|
||||||
realmId: kubernetes-realm
|
realmId: kubernetes-realm
|
||||||
groupId: users
|
groupId: f87d1c8e-32ee-4f63-9584-7fce67313137
|
||||||
members: ["admin", "eemoore"]
|
members: ["admin", "eemoore"]
|
||||||
providerConfigRef:
|
providerConfigRef:
|
||||||
name: keycloak-provider
|
name: keycloak-provider
|
||||||
|
|
|
||||||
|
|
@ -97,60 +97,172 @@ spec:
|
||||||
stringData:
|
stringData:
|
||||||
password: "thefi9paechooh"
|
password: "thefi9paechooh"
|
||||||
---
|
---
|
||||||
# Keycloak Helm release
|
# PostgreSQL credentials
|
||||||
apiVersion: helm.crossplane.io/v1beta1
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
kind: Release
|
kind: Object
|
||||||
metadata:
|
metadata:
|
||||||
name: keycloak
|
name: keycloak-postgresql-secret
|
||||||
namespace: crossplane-system
|
namespace: crossplane-system
|
||||||
spec:
|
spec:
|
||||||
providerConfigRef:
|
providerConfigRef:
|
||||||
name: helm-provider
|
name: kubernetes-provider
|
||||||
forProvider:
|
forProvider:
|
||||||
chart:
|
manifest:
|
||||||
name: keycloak
|
apiVersion: v1
|
||||||
repository: https://codecentric.github.io/helm-charts
|
kind: Secret
|
||||||
version: 18.10.0
|
metadata:
|
||||||
|
name: keycloak-postgresql
|
||||||
namespace: auth-system
|
namespace: auth-system
|
||||||
values:
|
type: Opaque
|
||||||
image:
|
stringData:
|
||||||
repository: quay.io/keycloak/keycloak
|
postgresql-password: "keycloak-db-password"
|
||||||
tag: 24.0.4
|
POSTGRES_PASSWORD: "keycloak-db-password"
|
||||||
serviceAccount:
|
POSTGRES_USER: "keycloak"
|
||||||
create: false
|
POSTGRES_DB: "keycloak"
|
||||||
|
---
|
||||||
|
# PostgreSQL StatefulSet
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-postgresql-statefulset
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: keycloak-postgresql
|
||||||
|
namespace: auth-system
|
||||||
|
spec:
|
||||||
|
serviceName: keycloak-postgresql
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: keycloak-postgresql
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: keycloak-postgresql
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgresql
|
||||||
|
image: postgres:17-bookworm
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
name: postgresql
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: keycloak-postgresql
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
subPath: pgdata
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- pg_isready
|
||||||
|
- -U
|
||||||
|
- keycloak
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- pg_isready
|
||||||
|
- -U
|
||||||
|
- keycloak
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: civo-volume
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
|
---
|
||||||
|
# PostgreSQL Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-postgresql-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: keycloak-postgresql
|
||||||
|
namespace: auth-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: keycloak-postgresql
|
||||||
|
ports:
|
||||||
|
- name: postgresql
|
||||||
|
port: 5432
|
||||||
|
targetPort: 5432
|
||||||
|
type: ClusterIP
|
||||||
|
---
|
||||||
|
# Keycloak Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
name: keycloak
|
name: keycloak
|
||||||
|
namespace: auth-system
|
||||||
|
labels:
|
||||||
|
app: keycloak
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: keycloak
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: keycloak
|
||||||
|
spec:
|
||||||
|
serviceAccountName: keycloak
|
||||||
|
containers:
|
||||||
|
- name: keycloak
|
||||||
|
image: quay.io/keycloak/keycloak:24.0.4
|
||||||
args:
|
args:
|
||||||
- start
|
- start
|
||||||
- --db=postgres
|
- --db=postgres
|
||||||
|
- --hostname=auth.nge6.com
|
||||||
- --hostname-strict=false
|
- --hostname-strict=false
|
||||||
- --hostname-strict-https=false
|
- --hostname-strict-https=false
|
||||||
- --proxy=edge
|
- --proxy=edge
|
||||||
- --http-enabled=true
|
- --http-enabled=true
|
||||||
livenessProbe: |
|
ports:
|
||||||
httpGet:
|
- containerPort: 8080
|
||||||
path: /realms/master
|
name: http
|
||||||
port: http
|
env:
|
||||||
initialDelaySeconds: 120
|
|
||||||
timeoutSeconds: 5
|
|
||||||
periodSeconds: 30
|
|
||||||
failureThreshold: 10
|
|
||||||
readinessProbe: |
|
|
||||||
httpGet:
|
|
||||||
path: /realms/master
|
|
||||||
port: http
|
|
||||||
initialDelaySeconds: 90
|
|
||||||
timeoutSeconds: 3
|
|
||||||
periodSeconds: 10
|
|
||||||
failureThreshold: 10
|
|
||||||
startupProbe: |
|
|
||||||
httpGet:
|
|
||||||
path: /realms/master
|
|
||||||
port: http
|
|
||||||
initialDelaySeconds: 60
|
|
||||||
timeoutSeconds: 3
|
|
||||||
periodSeconds: 5
|
|
||||||
failureThreshold: 30
|
|
||||||
extraEnv: |
|
|
||||||
- name: KEYCLOAK_ADMIN
|
- name: KEYCLOAK_ADMIN
|
||||||
value: admin
|
value: admin
|
||||||
- name: KEYCLOAK_ADMIN_PASSWORD
|
- name: KEYCLOAK_ADMIN_PASSWORD
|
||||||
|
|
@ -169,8 +281,62 @@ spec:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: keycloak-postgresql
|
name: keycloak-postgresql
|
||||||
key: postgresql-password
|
key: postgresql-password
|
||||||
ingress:
|
resources:
|
||||||
enabled: false
|
requests:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 1Gi
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /realms/master
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 90
|
||||||
|
timeoutSeconds: 3
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /realms/master
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 120
|
||||||
|
timeoutSeconds: 5
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 10
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /realms/master
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
timeoutSeconds: 3
|
||||||
|
periodSeconds: 5
|
||||||
|
failureThreshold: 30
|
||||||
|
---
|
||||||
|
# Keycloak Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: keycloak-http
|
||||||
|
namespace: auth-system
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: keycloak
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 8080
|
||||||
|
type: ClusterIP
|
||||||
---
|
---
|
||||||
# Keycloak SSL Certificate
|
# Keycloak SSL Certificate
|
||||||
apiVersion: kubernetes.crossplane.io/v1alpha2
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
|
@ -214,6 +380,7 @@ spec:
|
||||||
namespace: emissary
|
namespace: emissary
|
||||||
annotations:
|
annotations:
|
||||||
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
spec:
|
spec:
|
||||||
hostname: auth.nge6.com
|
hostname: auth.nge6.com
|
||||||
tlsSecret:
|
tlsSecret:
|
||||||
|
|
|
||||||
73
cluster-autoscaler.yaml
Normal file
73
cluster-autoscaler.yaml
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Cluster autoscaler - Crossplane-managed to prevent marketplace overwriting config
|
||||||
|
# Main pool (fc94): fixed at 3 nodes
|
||||||
|
# High-compute pool (cc28): scales 0-5 based on demand
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: cluster-autoscaler-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: cluster-autoscaler
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
app: cluster-autoscaler
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: cluster-autoscaler
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: cluster-autoscaler
|
||||||
|
spec:
|
||||||
|
serviceAccountName: cluster-autoscaler
|
||||||
|
containers:
|
||||||
|
- name: cluster-autoscaler
|
||||||
|
image: registry.k8s.io/autoscaling/cluster-autoscaler:v1.28.1
|
||||||
|
command:
|
||||||
|
- ./cluster-autoscaler
|
||||||
|
- --v=4
|
||||||
|
- --stderrthreshold=info
|
||||||
|
- --cloud-provider=civo
|
||||||
|
- --nodes=3:3:1b886eac-942e-40bf-8f70-7a5496f2fd3b
|
||||||
|
- --nodes=0:1:high-compute
|
||||||
|
- --skip-nodes-with-local-storage=false
|
||||||
|
- --skip-nodes-with-system-pods=false
|
||||||
|
- --scale-down-unneeded-time=5m
|
||||||
|
- --scale-down-delay-after-add=5m
|
||||||
|
env:
|
||||||
|
- name: CIVO_API_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: api-url
|
||||||
|
name: civo-api-access
|
||||||
|
- name: CIVO_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: api-key
|
||||||
|
name: civo-api-access
|
||||||
|
- name: CIVO_CLUSTER_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: cluster-id
|
||||||
|
name: civo-api-access
|
||||||
|
- name: CIVO_REGION
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: region
|
||||||
|
name: civo-api-access
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
|
|
@ -47,6 +47,10 @@ spec:
|
||||||
LFS_START_SERVER = true
|
LFS_START_SERVER = true
|
||||||
OFFLINE_MODE = false
|
OFFLINE_MODE = false
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
ENABLED = true
|
||||||
|
CONTAINER_REGISTRY_TOKEN_REALM = https://registry.nge6.com
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
DB_TYPE = sqlite3
|
DB_TYPE = sqlite3
|
||||||
PATH = /data/gitea/gitea.db
|
PATH = /data/gitea/gitea.db
|
||||||
|
|
@ -305,6 +309,6 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
hostname: git.nge6.com
|
hostname: git.nge6.com
|
||||||
prefix: /
|
prefix: /
|
||||||
service: https://pomerium-proxy.pomerium:443
|
service: http://pomerium-allinone.pomerium:443
|
||||||
timeout_ms: 30000
|
timeout_ms: 30000
|
||||||
connect_timeout_ms: 10000
|
connect_timeout_ms: 10000
|
||||||
70
keycloak-auth-dns.yaml
Normal file
70
keycloak-auth-dns.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# SSL Certificate for auth.nge6.com (Keycloak alternative)
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-auth-certificate
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: keycloak-auth-tls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
secretName: keycloak-auth-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-dns
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- auth.nge6.com
|
||||||
|
---
|
||||||
|
# Ambassador Host for auth.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-auth-host
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Host
|
||||||
|
metadata:
|
||||||
|
name: keycloak-auth-host
|
||||||
|
namespace: emissary
|
||||||
|
annotations:
|
||||||
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
|
spec:
|
||||||
|
hostname: auth.nge6.com
|
||||||
|
tlsSecret:
|
||||||
|
name: keycloak-auth-tls
|
||||||
|
---
|
||||||
|
# Ambassador Mapping for auth.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-auth-mapping
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Mapping
|
||||||
|
metadata:
|
||||||
|
name: keycloak-auth-mapping
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
hostname: auth.nge6.com
|
||||||
|
prefix: /
|
||||||
|
service: keycloak-http.auth-system:80
|
||||||
|
timeout_ms: 30000
|
||||||
|
connect_timeout_ms: 10000
|
||||||
47
keycloak-dns-fix.yaml
Normal file
47
keycloak-dns-fix.yaml
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Fix DNS resolution for keycloak.nge6.com from inside cluster
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-internal-dns
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-com
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
type: ExternalName
|
||||||
|
externalName: keycloak-http.auth-system.svc.cluster.local
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
---
|
||||||
|
# Add custom hosts entry to CoreDNS
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: coredns-custom-hosts
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: coredns-custom
|
||||||
|
namespace: kube-system
|
||||||
|
data:
|
||||||
|
keycloak.override: |
|
||||||
|
keycloak.nge6.com:53 {
|
||||||
|
hosts {
|
||||||
|
212.2.241.28 keycloak.nge6.com
|
||||||
|
fallthrough
|
||||||
|
}
|
||||||
|
}
|
||||||
70
keycloak-nge6-dns.yaml
Normal file
70
keycloak-nge6-dns.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# SSL Certificate for keycloak.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-certificate
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-tls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
secretName: keycloak-nge6-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-dns
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- keycloak.nge6.com
|
||||||
|
---
|
||||||
|
# Ambassador Host for keycloak.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-host
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Host
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-host
|
||||||
|
namespace: emissary
|
||||||
|
annotations:
|
||||||
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
|
spec:
|
||||||
|
hostname: keycloak.nge6.com
|
||||||
|
tlsSecret:
|
||||||
|
name: keycloak-nge6-tls
|
||||||
|
---
|
||||||
|
# Ambassador Mapping for keycloak.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-mapping
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Mapping
|
||||||
|
metadata:
|
||||||
|
name: keycloak-nge6-mapping
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
hostname: keycloak.nge6.com
|
||||||
|
prefix: /
|
||||||
|
service: keycloak-http.auth-system:80
|
||||||
|
timeout_ms: 30000
|
||||||
|
connect_timeout_ms: 10000
|
||||||
|
|
@ -7,6 +7,7 @@ resources:
|
||||||
- provider-configs.yaml
|
- provider-configs.yaml
|
||||||
- namespaces.yaml
|
- namespaces.yaml
|
||||||
- external-dns.yaml
|
- external-dns.yaml
|
||||||
|
- ambassador-listeners.yaml
|
||||||
|
|
||||||
# Certificate management
|
# Certificate management
|
||||||
- cert-manager/
|
- cert-manager/
|
||||||
|
|
@ -20,8 +21,13 @@ resources:
|
||||||
|
|
||||||
# Applications
|
# Applications
|
||||||
- forgejo-k8s.yaml
|
- forgejo-k8s.yaml
|
||||||
- pomerium.yaml
|
- pomerium-allinone.yaml
|
||||||
|
- pomerium-dns.yaml
|
||||||
- vaultwarden.yaml
|
- vaultwarden.yaml
|
||||||
|
- keycloak-nge6-dns.yaml
|
||||||
|
|
||||||
|
# Argo Workflows
|
||||||
|
- argo-workflows/
|
||||||
|
|
||||||
# Exclude problematic directories:
|
# Exclude problematic directories:
|
||||||
# - flux/ (managed by Flux itself)
|
# - flux/ (managed by Flux itself)
|
||||||
|
|
|
||||||
127
node-labeler.yaml
Normal file
127
node-labeler.yaml
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
# Node labeler - automatically labels nodes by pool based on name pattern
|
||||||
|
# fc94 in node name -> main pool (1b886eac...)
|
||||||
|
# cc28 in node name -> high-compute pool
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: node-labeler-sa
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: node-labeler
|
||||||
|
namespace: kube-system
|
||||||
|
---
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: node-labeler-clusterrole
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: node-labeler
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [nodes]
|
||||||
|
verbs: [get, list, patch]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: [pods]
|
||||||
|
verbs: [get, list, watch]
|
||||||
|
---
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: node-labeler-clusterrolebinding
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: node-labeler
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: node-labeler
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: node-labeler
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
---
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: node-labeler-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: node-labeler
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: node-labeler
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: node-labeler
|
||||||
|
spec:
|
||||||
|
serviceAccountName: node-labeler
|
||||||
|
containers:
|
||||||
|
- name: labeler
|
||||||
|
image: bitnami/kubectl:latest
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
while true; do
|
||||||
|
for NODE in $(kubectl get nodes -o jsonpath='{.items[*].metadata.name}'); do
|
||||||
|
# Skip if already labeled
|
||||||
|
POOL=$(kubectl get node "$NODE" -o jsonpath='{.metadata.labels.kubernetes\.civo\.com/node-pool}' 2>/dev/null)
|
||||||
|
if [ -n "$POOL" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Label based on name pattern
|
||||||
|
if echo "$NODE" | grep -q "fc94"; then
|
||||||
|
echo "Labeling $NODE as main pool"
|
||||||
|
kubectl label node "$NODE" \
|
||||||
|
kubernetes.civo.com/node-pool=1b886eac-942e-40bf-8f70-7a5496f2fd3b \
|
||||||
|
kubernetes.civo.com/node-size=g4s.kube.medium --overwrite
|
||||||
|
elif echo "$NODE" | grep -q "cc28"; then
|
||||||
|
echo "Labeling $NODE as high-compute pool"
|
||||||
|
kubectl label node "$NODE" \
|
||||||
|
kubernetes.civo.com/node-pool=high-compute \
|
||||||
|
kubernetes.civo.com/node-size=g4c.kube.small --overwrite
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
sleep 30
|
||||||
|
done
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
181
pomerium-allinone.yaml
Normal file
181
pomerium-allinone.yaml
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
# Pomerium All-In-One Deployment (single process, no Helm)
|
||||||
|
|
||||||
|
# ConfigMap for Pomerium configuration
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-allinone-config
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: pomerium-allinone
|
||||||
|
namespace: pomerium
|
||||||
|
data:
|
||||||
|
config.yaml: |
|
||||||
|
# Core configuration
|
||||||
|
address: :443
|
||||||
|
http_redirect_addr: :80
|
||||||
|
|
||||||
|
# Security keys (32 bytes base64)
|
||||||
|
shared_secret: 5Cz7gj71G5ujzH9HIc1XgwabUXCdJ3st9649gNlknrI=
|
||||||
|
cookie_secret: SXzBgU9L72OI+QCD9lEOxXcjApyE+4oIbetqtveNcjc=
|
||||||
|
|
||||||
|
# Run in insecure mode (no TLS certs required)
|
||||||
|
insecure_server: true
|
||||||
|
|
||||||
|
# Service URLs (internal)
|
||||||
|
authenticate_service_url: https://authenticate.nge6.com
|
||||||
|
|
||||||
|
# Identity provider
|
||||||
|
idp_provider: oidc
|
||||||
|
idp_provider_url: https://auth.nge6.com/realms/kubernetes-realm
|
||||||
|
idp_client_id: pomerium
|
||||||
|
idp_client_secret: U3Elh0oZEazKRpHpIasgP8yovUGsvq5K
|
||||||
|
idp_scopes:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
- email
|
||||||
|
|
||||||
|
# Routes
|
||||||
|
routes:
|
||||||
|
# Keycloak admin
|
||||||
|
- from: https://keycloak.nge6.com
|
||||||
|
to: http://keycloak-http.auth-system.svc.cluster.local
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
|
||||||
|
# Vaultwarden SSO/OAuth endpoints only (needed for authentication flow)
|
||||||
|
- from: https://vault.nge6.com
|
||||||
|
to: http://vaultwarden-http.vaultwarden.svc.cluster.local:8080
|
||||||
|
prefix: /identity/connect
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
|
||||||
|
- from: https://vault.nge6.com
|
||||||
|
to: http://vaultwarden-http.vaultwarden.svc.cluster.local:8080
|
||||||
|
prefix: /identity/sso
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
|
||||||
|
# Vaultwarden API endpoints (protected by Vaultwarden's own auth)
|
||||||
|
- from: https://vault.nge6.com
|
||||||
|
to: http://vaultwarden-http.vaultwarden.svc.cluster.local:8080
|
||||||
|
prefix: /api
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
|
||||||
|
# Vaultwarden web UI - requires Pomerium authentication
|
||||||
|
- from: https://vault.nge6.com
|
||||||
|
to: http://vaultwarden-http.vaultwarden.svc.cluster.local:8080
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_any_authenticated_user: true
|
||||||
|
|
||||||
|
# Forgejo container registry token endpoint (Docker auth)
|
||||||
|
- from: https://git.nge6.com
|
||||||
|
to: http://forgejo-http.forgejo.svc.cluster.local:3000
|
||||||
|
prefix: /v2/token
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
|
||||||
|
# Forgejo Git - requires authentication
|
||||||
|
- from: https://git.nge6.com
|
||||||
|
to: http://forgejo-http.forgejo.svc.cluster.local:3000
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_any_authenticated_user: true
|
||||||
|
|
||||||
|
# Argo Workflows UI - requires authentication
|
||||||
|
- from: https://workflows.nge6.com
|
||||||
|
to: http://argo-server.argo.svc.cluster.local:2746
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_any_authenticated_user: true
|
||||||
|
|
||||||
|
---
|
||||||
|
# Pomerium All-In-One Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-allinone-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pomerium-allinone
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pomerium-allinone
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pomerium-allinone
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pomerium
|
||||||
|
image: pomerium/pomerium:v0.25.0
|
||||||
|
args:
|
||||||
|
- --config=/etc/pomerium/config.yaml
|
||||||
|
env:
|
||||||
|
# Run all services in one container
|
||||||
|
- name: SERVICES
|
||||||
|
value: all
|
||||||
|
- name: INSECURE_SERVER
|
||||||
|
value: "true"
|
||||||
|
ports:
|
||||||
|
- containerPort: 443
|
||||||
|
name: https
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/pomerium
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 512Mi
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: pomerium-allinone
|
||||||
|
---
|
||||||
|
# Pomerium All-In-One Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-allinone-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pomerium-allinone
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: pomerium-allinone
|
||||||
|
ports:
|
||||||
|
- name: https
|
||||||
|
port: 443
|
||||||
|
targetPort: 443
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
71
pomerium-dns.yaml
Normal file
71
pomerium-dns.yaml
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
# DNS and SSL for Pomerium authenticate endpoint
|
||||||
|
# SSL Certificate for authenticate.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-certificate
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-tls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
secretName: pomerium-authenticate-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-dns
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- authenticate.nge6.com
|
||||||
|
---
|
||||||
|
# Ambassador Host for authenticate.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-host
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Host
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-host
|
||||||
|
namespace: emissary
|
||||||
|
annotations:
|
||||||
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
|
spec:
|
||||||
|
hostname: authenticate.nge6.com
|
||||||
|
tlsSecret:
|
||||||
|
name: pomerium-authenticate-tls
|
||||||
|
---
|
||||||
|
# Ambassador Mapping for authenticate.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-mapping
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v3alpha1
|
||||||
|
kind: Mapping
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-mapping
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
hostname: authenticate.nge6.com
|
||||||
|
prefix: /
|
||||||
|
service: http://pomerium-allinone.pomerium:443
|
||||||
|
timeout_ms: 30000
|
||||||
|
connect_timeout_ms: 10000
|
||||||
397
pomerium-native.yaml
Normal file
397
pomerium-native.yaml
Normal file
|
|
@ -0,0 +1,397 @@
|
||||||
|
# Pomerium Native Kubernetes Deployment (No Helm!)
|
||||||
|
# Namespace already exists from previous deployment
|
||||||
|
|
||||||
|
# ConfigMap for Pomerium configuration
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-config
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: pomerium
|
||||||
|
namespace: pomerium
|
||||||
|
data:
|
||||||
|
config.yaml: |
|
||||||
|
# Core configuration
|
||||||
|
address: :443
|
||||||
|
grpc_address: :5443
|
||||||
|
|
||||||
|
# Security keys
|
||||||
|
shared_secret: 5Cz7gj71G5ujzH9HIc1XgwabUXCdJ3st9649gNlknrI=
|
||||||
|
cookie_secret: SXzBgU9L72OI+QCD9lEOxXcjApyE+4oIbetqtveNcjc=
|
||||||
|
|
||||||
|
# Service URLs
|
||||||
|
authenticate_service_url: https://authenticate.nge6.com
|
||||||
|
authorize_service_url: http://pomerium-authorize.pomerium.svc.cluster.local:5443
|
||||||
|
databroker_service_url: http://pomerium-databroker.pomerium.svc.cluster.local:5443
|
||||||
|
|
||||||
|
# Run in insecure mode for internal cluster communication
|
||||||
|
insecure_server: true
|
||||||
|
|
||||||
|
# Identity provider
|
||||||
|
idp_provider: oidc
|
||||||
|
idp_provider_url: https://keycloak.nge6.com/realms/kubernetes-realm
|
||||||
|
idp_client_id: pomerium
|
||||||
|
idp_client_secret: 3JFMh3DZDOYlNiSQ64abL0z0bw1WJt3x
|
||||||
|
idp_scopes:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
- email
|
||||||
|
|
||||||
|
# Routes
|
||||||
|
routes:
|
||||||
|
# Keycloak admin (public for initial setup)
|
||||||
|
- from: https://keycloak.nge6.com
|
||||||
|
to: http://keycloak-http.auth-system.svc.cluster.local
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
|
||||||
|
# Vaultwarden - requires authentication
|
||||||
|
- from: https://vault.nge6.com
|
||||||
|
to: http://vaultwarden-http.vaultwarden.svc.cluster.local:8080
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_any_authenticated_user: true
|
||||||
|
|
||||||
|
# Forgejo Git - requires authentication
|
||||||
|
- from: https://git.nge6.com
|
||||||
|
to: http://forgejo-http.forgejo.svc.cluster.local:3000
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_any_authenticated_user: true
|
||||||
|
|
||||||
|
# Authentication endpoint
|
||||||
|
- from: https://authenticate.nge6.com
|
||||||
|
to: http://pomerium-authenticate.pomerium.svc.cluster.local
|
||||||
|
allow_public_unauthenticated_access: true
|
||||||
|
---
|
||||||
|
# Pomerium Authenticate Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pomerium-authenticate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pomerium-authenticate
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pomerium
|
||||||
|
image: pomerium/pomerium:v0.25.0
|
||||||
|
args:
|
||||||
|
- --config=/etc/pomerium/config.yaml
|
||||||
|
env:
|
||||||
|
- name: SERVICES
|
||||||
|
value: authenticate
|
||||||
|
- name: INSECURE_SERVER
|
||||||
|
value: "true"
|
||||||
|
- name: ADDRESS
|
||||||
|
value: :80
|
||||||
|
- name: GRPC_ADDRESS
|
||||||
|
value: :5443
|
||||||
|
- name: GRPC_INSECURE
|
||||||
|
value: "true"
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
- containerPort: 5443
|
||||||
|
name: grpc
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/pomerium
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: pomerium
|
||||||
|
---
|
||||||
|
# Pomerium Authenticate Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authenticate
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: pomerium-authenticate
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
- name: grpc
|
||||||
|
port: 5443
|
||||||
|
targetPort: 5443
|
||||||
|
---
|
||||||
|
# Pomerium Authorize Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authorize-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authorize
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pomerium-authorize
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pomerium-authorize
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pomerium
|
||||||
|
image: pomerium/pomerium:v0.25.0
|
||||||
|
args:
|
||||||
|
- --config=/etc/pomerium/config.yaml
|
||||||
|
env:
|
||||||
|
- name: SERVICES
|
||||||
|
value: authorize
|
||||||
|
- name: INSECURE_SERVER
|
||||||
|
value: "true"
|
||||||
|
- name: ADDRESS
|
||||||
|
value: :80
|
||||||
|
- name: GRPC_ADDRESS
|
||||||
|
value: :5443
|
||||||
|
- name: GRPC_INSECURE
|
||||||
|
value: "true"
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
- containerPort: 5443
|
||||||
|
name: grpc
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/pomerium
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: pomerium
|
||||||
|
---
|
||||||
|
# Pomerium Authorize Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authorize-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pomerium-authorize
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: pomerium-authorize
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
- name: grpc
|
||||||
|
port: 5443
|
||||||
|
targetPort: 5443
|
||||||
|
---
|
||||||
|
# Pomerium Databroker Deployment
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-databroker-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pomerium-databroker
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pomerium-databroker
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pomerium-databroker
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pomerium
|
||||||
|
image: pomerium/pomerium:v0.25.0
|
||||||
|
args:
|
||||||
|
- --config=/etc/pomerium/config.yaml
|
||||||
|
env:
|
||||||
|
- name: SERVICES
|
||||||
|
value: databroker
|
||||||
|
- name: INSECURE_SERVER
|
||||||
|
value: "true"
|
||||||
|
- name: ADDRESS
|
||||||
|
value: :80
|
||||||
|
- name: GRPC_ADDRESS
|
||||||
|
value: :5443
|
||||||
|
- name: GRPC_INSECURE
|
||||||
|
value: "true"
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
- containerPort: 5443
|
||||||
|
name: grpc
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/pomerium
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: pomerium
|
||||||
|
---
|
||||||
|
# Pomerium Databroker Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-databroker-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pomerium-databroker
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: pomerium-databroker
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
- name: grpc
|
||||||
|
port: 5443
|
||||||
|
targetPort: 5443
|
||||||
|
---
|
||||||
|
# Pomerium Proxy Deployment (the main ingress point)
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-proxy-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pomerium-proxy
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pomerium-proxy
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pomerium-proxy
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pomerium
|
||||||
|
image: pomerium/pomerium:v0.25.0
|
||||||
|
args:
|
||||||
|
- --config=/etc/pomerium/config.yaml
|
||||||
|
env:
|
||||||
|
- name: SERVICES
|
||||||
|
value: proxy
|
||||||
|
- name: INSECURE_SERVER
|
||||||
|
value: "true"
|
||||||
|
- name: ADDRESS
|
||||||
|
value: :443
|
||||||
|
- name: HTTP_REDIRECT_ADDR
|
||||||
|
value: :80
|
||||||
|
ports:
|
||||||
|
- containerPort: 443
|
||||||
|
name: https
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/pomerium
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: pomerium
|
||||||
|
---
|
||||||
|
# Pomerium Proxy Service
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pomerium-proxy-service
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pomerium-proxy
|
||||||
|
namespace: pomerium
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: pomerium-proxy
|
||||||
|
ports:
|
||||||
|
- name: https
|
||||||
|
port: 443
|
||||||
|
targetPort: 443
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
|
@ -41,6 +41,11 @@ spec:
|
||||||
to: http://forgejo-http.forgejo.svc.cluster.local:3000
|
to: http://forgejo-http.forgejo.svc.cluster.local:3000
|
||||||
preserve_host_header: true
|
preserve_host_header: true
|
||||||
allow_any_authenticated_user: true
|
allow_any_authenticated_user: true
|
||||||
|
# Vaultwarden password manager - require authentication
|
||||||
|
- from: https://vault.nge6.com
|
||||||
|
to: http://vaultwarden-http.vaultwarden.svc.cluster.local:8080
|
||||||
|
preserve_host_header: true
|
||||||
|
allow_any_authenticated_user: true
|
||||||
|
|
||||||
# Authentication service configuration
|
# Authentication service configuration
|
||||||
authenticate:
|
authenticate:
|
||||||
|
|
|
||||||
91
pool-scaler.yaml
Normal file
91
pool-scaler.yaml
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
# Pool scaler - watches for pending Argo workflow pods and scales the
|
||||||
|
# high-compute pool via the Civo API. Handles scale-up from zero since
|
||||||
|
# the cluster autoscaler can't do this without a node template.
|
||||||
|
# The cluster autoscaler still handles scale-down.
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: pool-scaler-deployment
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pool-scaler
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pool-scaler
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pool-scaler
|
||||||
|
spec:
|
||||||
|
serviceAccountName: node-labeler
|
||||||
|
containers:
|
||||||
|
- name: scaler
|
||||||
|
image: bitnami/kubectl:latest
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "Pool scaler started. Watching for pending workflow pods..."
|
||||||
|
while true; do
|
||||||
|
# Count pending pods with high-compute nodeSelector
|
||||||
|
PENDING=$(kubectl get pods -n argo --field-selector=status.phase=Pending \
|
||||||
|
-o jsonpath='{.items[*].spec.nodeSelector}' 2>/dev/null \
|
||||||
|
| tr '}' '\n' | grep -c 'high-compute' || true)
|
||||||
|
|
||||||
|
if [ "$PENDING" -gt 0 ]; then
|
||||||
|
# Check if any high-compute nodes already exist
|
||||||
|
HC_NODES=$(kubectl get nodes -l kubernetes.civo.com/node-pool=high-compute --no-headers 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
if [ "$HC_NODES" -eq 0 ]; then
|
||||||
|
echo "$(date): $PENDING pending workflow pods, no high-compute nodes. Scaling pool to 1..."
|
||||||
|
curl -s -X PUT \
|
||||||
|
"${CIVO_API_URL}/v2/kubernetes/clusters/${CIVO_CLUSTER_ID}/pools/high-compute" \
|
||||||
|
-H "Authorization: bearer ${CIVO_API_KEY}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"count\": 1, \"region\": \"${CIVO_REGION}\"}"
|
||||||
|
echo ""
|
||||||
|
# Wait for node to provision before checking again
|
||||||
|
sleep 180
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 15
|
||||||
|
done
|
||||||
|
env:
|
||||||
|
- name: CIVO_API_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: api-url
|
||||||
|
name: civo-api-access
|
||||||
|
- name: CIVO_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: api-key
|
||||||
|
name: civo-api-access
|
||||||
|
- name: CIVO_CLUSTER_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: cluster-id
|
||||||
|
name: civo-api-access
|
||||||
|
- name: CIVO_REGION
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: region
|
||||||
|
name: civo-api-access
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
92
registry-internal.yaml
Normal file
92
registry-internal.yaml
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
# Internal registry access - no mTLS, Forgejo handles auth via imagePullSecret
|
||||||
|
# Only accessible via cluster-internal DNS (no external-dns annotation)
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-internal-certificate
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: registry-internal-tls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
secretName: registry-internal-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-dns
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- registry-internal.nge6.com
|
||||||
|
---
|
||||||
|
# Host without external-dns - only reachable if you know the IP
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-internal-host
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v2
|
||||||
|
kind: Host
|
||||||
|
metadata:
|
||||||
|
name: registry-internal-host
|
||||||
|
namespace: emissary
|
||||||
|
annotations:
|
||||||
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
|
spec:
|
||||||
|
hostname: registry-internal.nge6.com
|
||||||
|
tlsSecret:
|
||||||
|
name: registry-internal-tls
|
||||||
|
---
|
||||||
|
# Mapping direct to Forgejo - no Pomerium, no mTLS
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-internal-mapping
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v2
|
||||||
|
kind: Mapping
|
||||||
|
metadata:
|
||||||
|
name: registry-internal-mapping
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
host: registry-internal.nge6.com
|
||||||
|
prefix: /
|
||||||
|
service: http://forgejo-http.forgejo.svc.cluster.local:3000
|
||||||
|
timeout_ms: 300000
|
||||||
|
connect_timeout_ms: 10000
|
||||||
|
---
|
||||||
|
# imagePullSecret for argo namespace
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: argo-registry-pull-secret
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: forgejo-registry
|
||||||
|
namespace: argo
|
||||||
|
type: kubernetes.io/dockerconfigjson
|
||||||
|
stringData:
|
||||||
|
.dockerconfigjson: |
|
||||||
|
{"auths":{"registry-internal.nge6.com":{"username":"eemoore","password":"testpassword123!","auth":"ZWVtb29yZTp0ZXN0cGFzc3dvcmQxMjMh"}}}
|
||||||
97
registry.yaml
Normal file
97
registry.yaml
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# SSL Certificate for registry.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-certificate
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: registry-tls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
secretName: registry-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-dns
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- registry.nge6.com
|
||||||
|
---
|
||||||
|
# Ambassador Host for registry.nge6.com
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-host
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v2
|
||||||
|
kind: Host
|
||||||
|
metadata:
|
||||||
|
name: registry-host
|
||||||
|
namespace: emissary
|
||||||
|
annotations:
|
||||||
|
external-dns.ambassador-service: emissary-ingress.emissary.svc.cluster.local
|
||||||
|
external-dns.alpha.kubernetes.io/target: 212.2.241.28
|
||||||
|
spec:
|
||||||
|
hostname: registry.nge6.com
|
||||||
|
tlsSecret:
|
||||||
|
name: registry-tls
|
||||||
|
tlsContext:
|
||||||
|
name: registry-mtls
|
||||||
|
---
|
||||||
|
# TLSContext for mTLS - requires client certificates
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-tls-context
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v2
|
||||||
|
kind: TLSContext
|
||||||
|
metadata:
|
||||||
|
name: registry-mtls
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- registry.nge6.com
|
||||||
|
secret: registry-tls
|
||||||
|
ca_secret: registry-client-ca
|
||||||
|
cert_required: true
|
||||||
|
min_tls_version: v1.2
|
||||||
|
max_tls_version: v1.2
|
||||||
|
---
|
||||||
|
# Ambassador Mapping for registry - direct to Forgejo, no Pomerium
|
||||||
|
apiVersion: kubernetes.crossplane.io/v1alpha2
|
||||||
|
kind: Object
|
||||||
|
metadata:
|
||||||
|
name: registry-mapping
|
||||||
|
namespace: crossplane-system
|
||||||
|
spec:
|
||||||
|
providerConfigRef:
|
||||||
|
name: kubernetes-provider
|
||||||
|
forProvider:
|
||||||
|
manifest:
|
||||||
|
apiVersion: getambassador.io/v2
|
||||||
|
kind: Mapping
|
||||||
|
metadata:
|
||||||
|
name: registry-mapping
|
||||||
|
namespace: emissary
|
||||||
|
spec:
|
||||||
|
host: registry.nge6.com
|
||||||
|
prefix: /
|
||||||
|
service: http://forgejo-http.forgejo.svc.cluster.local:3000
|
||||||
|
timeout_ms: 300000
|
||||||
|
connect_timeout_ms: 10000
|
||||||
|
|
@ -37,9 +37,19 @@ spec:
|
||||||
ROCKET_WORKERS: "10"
|
ROCKET_WORKERS: "10"
|
||||||
# Security settings
|
# Security settings
|
||||||
INVITATIONS_ALLOWED: "true"
|
INVITATIONS_ALLOWED: "true"
|
||||||
SIGNUPS_ALLOWED: "false"
|
SIGNUPS_ALLOWED: "true"
|
||||||
SHOW_PASSWORD_HINT: "false"
|
SHOW_PASSWORD_HINT: "false"
|
||||||
# Email configuration (disabled)
|
# Email configuration (disabled)
|
||||||
|
# OIDC/SSO configuration
|
||||||
|
SSO_ENABLED: "true"
|
||||||
|
SSO_ONLY: "false"
|
||||||
|
SSO_CLIENT_ID: "vaultwarden"
|
||||||
|
SSO_CLIENT_SECRET: "zMeG3odq6GUBoYUVcoNl1CmngJpwgMS6"
|
||||||
|
SSO_AUTHORITY: "https://auth.nge6.com/realms/kubernetes-realm"
|
||||||
|
SSO_SCOPES: "openid email profile"
|
||||||
|
# SSO_MASTER_PASSWORD_POLICY removed - not valid in testing image
|
||||||
|
SSO_DOMAIN: "nge6.com"
|
||||||
|
SSO_ORGANIZATIONS_INVITE: "true"
|
||||||
# Admin settings
|
# Admin settings
|
||||||
ADMIN_TOKEN: "vaultwarden-admin-token-change-in-production"
|
ADMIN_TOKEN: "vaultwarden-admin-token-change-in-production"
|
||||||
# Database (using SQLite for simplicity)
|
# Database (using SQLite for simplicity)
|
||||||
|
|
@ -93,6 +103,8 @@ spec:
|
||||||
app: vaultwarden
|
app: vaultwarden
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: vaultwarden
|
app: vaultwarden
|
||||||
|
|
@ -103,7 +115,7 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: vaultwarden
|
- name: vaultwarden
|
||||||
image: vaultwarden/server:1.30.5
|
image: vaultwarden/server:testing
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8080
|
- containerPort: 8080
|
||||||
name: http
|
name: http
|
||||||
|
|
@ -233,6 +245,6 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
hostname: vault.nge6.com
|
hostname: vault.nge6.com
|
||||||
prefix: /
|
prefix: /
|
||||||
service: https://pomerium-proxy.pomerium:443
|
service: http://pomerium-allinone.pomerium:443
|
||||||
timeout_ms: 30000
|
timeout_ms: 30000
|
||||||
connect_timeout_ms: 10000
|
connect_timeout_ms: 10000
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue