Compare commits

..

1 Commits

Author SHA1 Message Date
91af01c2fa chore: Minecraft | clean up old servers 2025-11-24 20:20:37 +05:00
43 changed files with 11388 additions and 834 deletions

View File

@@ -1,41 +0,0 @@
import * as fs from "fs";
import * as path from "path";
import { Release } from "@cdktf/provider-helm/lib/release";
import { Construct } from "constructs";
import { PublicIngressRoute } from "../../utils";
import { Providers } from "../../types";
type GoCacheOptions = {
providers: Providers;
namespace: string;
name: string;
host: string;
};
export class GoCache extends Construct {
constructor(scope: Construct, id: string, opts: GoCacheOptions) {
super(scope, id);
const { namespace, name, host } = opts;
const { helm, kubernetes } = opts.providers;
new Release(this, "helm-release", {
provider: helm,
name,
namespace,
repository: "https://gomods.github.io/athens-charts",
chart: "athens-proxy",
values: [fs.readFileSync(path.join(__dirname, "values.yaml"), "utf8")],
});
new PublicIngressRoute(this, "ingress", {
provider: kubernetes,
namespace,
name,
host,
serviceName: `${name}-athens-proxy`,
servicePort: 80,
});
}
}

View File

@@ -1,20 +0,0 @@
replicaCount: 1
image:
runAsNonRoot: true
nodeSelector:
nodepool: worker
strategy:
type: Recreate
storage:
disk:
persistence:
enabled: true
accessMode: ReadWriteMany
size: 64Gi
storageClass: longhorn
configEnvVars:
- name: ATHENS_DOWNLOAD_MODE
value: "sync"
upstreamProxy:
enabled: true
url: "https://proxy.golang.org"

View File

@@ -5,23 +5,15 @@ import { NamespaceV1 } from "@cdktf/provider-kubernetes/lib/namespace-v1";
import { NixCache } from "./nix";
import { NpmCache } from "./npm";
import { PipCache } from "./pip";
import { GoCache } from "./go";
import { HelmProvider } from "@cdktf/provider-helm/lib/provider";
export class CacheInfrastructure extends TerraformStack {
constructor(scope: Construct, id: string) {
super(scope, id);
const kubernetes = new KubernetesProvider(this, "kubernetes", {
const provider = new KubernetesProvider(this, "kubernetes", {
configPath: "~/.kube/config",
});
const helm = new HelmProvider(this, "helm", {
kubernetes: {
configPath: "~/.kube/config",
},
});
const namespace = "package-cache";
new NamespaceV1(this, "package-cache-namespace", {
@@ -32,34 +24,24 @@ export class CacheInfrastructure extends TerraformStack {
// Add cache-related infrastructure components here
new NixCache(this, "nix-cache", {
provider: kubernetes,
provider,
namespace,
name: "nix-cache",
host: "nix.dogar.dev",
});
new NpmCache(this, "npm-cache", {
provider: kubernetes,
provider,
namespace,
name: "npm-cache",
host: "npm.dogar.dev",
});
new PipCache(this, "pip-cache", {
provider: kubernetes,
provider,
namespace,
name: "pip-cache",
host: "pip.dogar.dev",
});
new GoCache(this, "go-cache", {
providers: {
kubernetes,
helm,
},
namespace,
name: "go-cache",
host: "go.dogar.dev",
});
}
}

View File

@@ -73,7 +73,7 @@ export class NixCache extends Construct {
namespace,
},
spec: {
replicas: "1",
replicas: "3",
selector: {
matchLabels: {
app: name,

View File

@@ -70,7 +70,7 @@ export class NpmCache extends Construct {
namespace,
},
spec: {
replicas: "1",
replicas: "3",
selector: {
matchLabels: {
app: name,

View File

@@ -6,6 +6,7 @@ import { Construct } from "constructs";
type CertManagerOptions = {
provider: HelmProvider;
version: string;
name: string;
namespace: string;
};
@@ -14,12 +15,13 @@ export class CertManager extends Construct {
constructor(scope: Construct, id: string, options: CertManagerOptions) {
super(scope, id);
const { namespace, name, provider } = options;
const { namespace, name, version, provider } = options;
new Release(this, id, {
provider,
name,
namespace,
version,
repository: "https://charts.jetstack.io",
chart: "cert-manager",
createNamespace: true,

View File

@@ -1,11 +1,6 @@
crds:
enabled: true
keep: true
prometheus:
enabled: true
webhook:
timeoutSeconds: 4
enableCertificateOwnerRef: true
extraArgs:
- "--dns01-recursive-nameservers-only"
- "--dns01-recursive-nameservers=1.1.1.1:53"

View File

@@ -59,6 +59,7 @@ export class CoreServices extends TerraformStack {
provider: helm,
name: "cert-manager",
namespace,
version: "1.18.2",
});
}
}

View File

@@ -1,8 +1,13 @@
providers:
kubernetesCRD:
allowCrossNamespace: true
ingress:
ingressClass:
enabled: true
isDefaultClass: true
name: traefik
deployment:
replicas: 1
replicas: 3
podLabels:
app: traefik
nodeSelector:
@@ -18,11 +23,36 @@ topologySpreadConstraints:
matchLabels:
app: traefik
additionalArguments:
- "--entryPoints.ssh.address=:2222/tcp"
- "--entryPoints.ssh.address=:22/tcp"
- "--entryPoints.minecraft-gtnh.address=:25566/tcp"
- "--entryPoints.minecraft-tfg.address=:25567/tcp"
- "--entryPoints.minecraft-star-technology.address=:25568/tcp"
ports:
ssh:
port: 2222
exposedPort: 2222
name: ssh
port: 22
exposedPort: 22
expose:
default: true
protocol: TCP
minecraft-gtnh:
name: minecraft-gtnh
port: 25566
exposedPort: 25566
expose:
default: true
protocol: TCP
minecraft-tfg:
name: minecraft-tfg
port: 25567
exposedPort: 25567
expose:
default: true
protocol: TCP
minecraft-star-technology:
name: minecraft-star-technology
port: 25568
exposedPort: 25568
expose:
default: true
protocol: TCP

View File

@@ -1,13 +1,22 @@
---
apiVersion: onepassword.com/v1
kind: OnePasswordItem
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: kibana-authentik
name: elasticsearch-cert
namespace: elastic-system
annotations:
operator.1password.io/auto-restart: "true"
spec:
itemPath: "vaults/Lab/items/kibana-authentik"
secretName: elasticsearch-cert
privateKey:
algorithm: ECDSA
size: 384
usages:
- server auth
dnsNames:
- elastic.dogar.dev
issuerRef:
name: cloudflare-issuer
kind: ClusterIssuer
group: cert-manager.io
---
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
@@ -17,24 +26,18 @@ metadata:
spec:
version: 8.15.2
http:
service:
spec:
type: LoadBalancer
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: elastic.dogar.dev
tls:
certificate:
secretName: elasticsearch-es-http-tls-internal
# secureSettings:
# - secretName: kibana-authentik
# entries:
# - key: client-secret
# path: "xpack.security.authc.realms.oidc.authentik.rp.client_secret"
secretName: elasticsearch-cert
nodeSets:
- name: node
count: 3
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
limits:
memory: 8Gi
- name: master
count: 1
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
@@ -44,21 +47,6 @@ spec:
resources:
requests:
storage: 10Gi
storageClassName: longhorn
storageClassName: longhorn-crypto
config:
node.roles: ["master", "data"]
# xpack.security.authc.token.enabled: true
# xpack.security.authc.realms.oidc.authentik:
# order: 2
# rp.client_id: "atlY82FGIBYvUg87cnENzks5ft1AUUtIfQsXSDog"
# rp.response_type: code
# rp.redirect_uri: "https://kibana.dogar.dev/api/security/oidc/callback"
# op.issuer: "https://auth.dogar.dev/application/o/kibana/"
# op.authorization_endpoint: "https://auth.dogar.dev/application/o/authorize/"
# op.token_endpoint: "https://auth.dogar.dev/application/o/token/"
# op.jwkset_path: "https://auth.dogar.dev/application/o/kibana/jwks/"
# op.userinfo_endpoint: "https://auth.dogar.dev/application/o/userinfo/"
# op.endsession_endpoint: "https://auth.dogar.dev/application/o/kibana/end-session/"
# rp.post_logout_redirect_uri: "https://kibana.dogar.dev/security/logged_out"
# claims.principal: sub
# claims.groups: groups

10248
elasticsearch/crds.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +0,0 @@
---
apiVersion: kibana.k8s.elastic.co/v1beta1
kind: Kibana
metadata:
name: kibana
namespace: elastic-system
spec:
version: 8.15.2
count: 1
elasticsearchRef:
name: elasticsearch
http:
tls:
certificate:
secretName: kibana-kb-http-tls-internal
config:
server.publicBaseUrl: "https://kibana.dogar.dev"
xpack.security.authc.providers:
# oidc.authentik:
# order: 0
# realm: authentik
# description: "Log in with Authentik"
basic.basic1:
order: 1

796
elasticsearch/operator.yaml Normal file
View File

@@ -0,0 +1,796 @@
# Source: eck-operator/templates/operator-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: elastic-system
labels:
name: elastic-system
---
# Source: eck-operator/templates/service-account.yaml
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: true
metadata:
name: elastic-operator
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
---
# Source: eck-operator/templates/webhook.yaml
apiVersion: v1
kind: Secret
metadata:
name: elastic-webhook-server-cert
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
---
# Source: eck-operator/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: elastic-operator
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
data:
eck.yaml: |-
log-verbosity: 0
metrics-port: 0
container-registry: docker.elastic.co
max-concurrent-reconciles: 3
ca-cert-validity: 8760h
ca-cert-rotate-before: 24h
cert-validity: 8760h
cert-rotate-before: 24h
disable-config-watch: false
exposed-node-labels: [topology.kubernetes.io/.*,failure-domain.beta.kubernetes.io/.*]
set-default-security-context: auto-detect
kube-client-timeout: 60s
elasticsearch-client-timeout: 180s
disable-telemetry: false
distribution-channel: all-in-one
validate-storage-class: true
enable-webhook: true
webhook-name: elastic-webhook.k8s.elastic.co
webhook-port: 9443
operator-namespace: elastic-system
enable-leader-election: true
elasticsearch-observation-interval: 10s
ubi-only: false
---
# Source: eck-operator/templates/cluster-roles.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: elastic-operator
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
rules:
- apiGroups:
- "authorization.k8s.io"
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- coordination.k8s.io
resources:
- leases
resourceNames:
- elastic-operator-leader
verbs:
- get
- watch
- update
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
- events
- persistentvolumeclaims
- secrets
- services
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- apps
resources:
- deployments
- statefulsets
- daemonsets
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- elasticsearch.k8s.elastic.co
resources:
- elasticsearches
- elasticsearches/status
- elasticsearches/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- autoscaling.k8s.elastic.co
resources:
- elasticsearchautoscalers
- elasticsearchautoscalers/status
- elasticsearchautoscalers/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- kibana.k8s.elastic.co
resources:
- kibanas
- kibanas/status
- kibanas/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- apm.k8s.elastic.co
resources:
- apmservers
- apmservers/status
- apmservers/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- enterprisesearch.k8s.elastic.co
resources:
- enterprisesearches
- enterprisesearches/status
- enterprisesearches/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- beat.k8s.elastic.co
resources:
- beats
- beats/status
- beats/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- agent.k8s.elastic.co
resources:
- agents
- agents/status
- agents/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- maps.k8s.elastic.co
resources:
- elasticmapsservers
- elasticmapsservers/status
- elasticmapsservers/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- stackconfigpolicy.k8s.elastic.co
resources:
- stackconfigpolicies
- stackconfigpolicies/status
- stackconfigpolicies/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- logstash.k8s.elastic.co
resources:
- logstashes
- logstashes/status
- logstashes/finalizers # needed for ownerReferences with blockOwnerDeletion on OCP
verbs:
- get
- list
- watch
- create
- update
- patch
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
verbs:
- get
- list
- watch
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
---
# Source: eck-operator/templates/cluster-roles.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: "elastic-operator-view"
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rbac.authorization.k8s.io/aggregate-to-admin: "true"
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
rules:
- apiGroups: ["elasticsearch.k8s.elastic.co"]
resources: ["elasticsearches"]
verbs: ["get", "list", "watch"]
- apiGroups: ["autoscaling.k8s.elastic.co"]
resources: ["elasticsearchautoscalers"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apm.k8s.elastic.co"]
resources: ["apmservers"]
verbs: ["get", "list", "watch"]
- apiGroups: ["kibana.k8s.elastic.co"]
resources: ["kibanas"]
verbs: ["get", "list", "watch"]
- apiGroups: ["enterprisesearch.k8s.elastic.co"]
resources: ["enterprisesearches"]
verbs: ["get", "list", "watch"]
- apiGroups: ["beat.k8s.elastic.co"]
resources: ["beats"]
verbs: ["get", "list", "watch"]
- apiGroups: ["agent.k8s.elastic.co"]
resources: ["agents"]
verbs: ["get", "list", "watch"]
- apiGroups: ["maps.k8s.elastic.co"]
resources: ["elasticmapsservers"]
verbs: ["get", "list", "watch"]
- apiGroups: ["stackconfigpolicy.k8s.elastic.co"]
resources: ["stackconfigpolicies"]
verbs: ["get", "list", "watch"]
- apiGroups: ["logstash.k8s.elastic.co"]
resources: ["logstashes"]
verbs: ["get", "list", "watch"]
---
# Source: eck-operator/templates/cluster-roles.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: "elastic-operator-edit"
labels:
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rbac.authorization.k8s.io/aggregate-to-admin: "true"
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
rules:
- apiGroups: ["elasticsearch.k8s.elastic.co"]
resources: ["elasticsearches"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["autoscaling.k8s.elastic.co"]
resources: ["elasticsearchautoscalers"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["apm.k8s.elastic.co"]
resources: ["apmservers"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["kibana.k8s.elastic.co"]
resources: ["kibanas"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["enterprisesearch.k8s.elastic.co"]
resources: ["enterprisesearches"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["beat.k8s.elastic.co"]
resources: ["beats"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["agent.k8s.elastic.co"]
resources: ["agents"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["maps.k8s.elastic.co"]
resources: ["elasticmapsservers"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["stackconfigpolicy.k8s.elastic.co"]
resources: ["stackconfigpolicies"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
- apiGroups: ["logstash.k8s.elastic.co"]
resources: ["logstashes"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
---
# Source: eck-operator/templates/role-bindings.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: elastic-operator
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: elastic-operator
subjects:
- kind: ServiceAccount
name: elastic-operator
namespace: elastic-system
---
# Source: eck-operator/templates/webhook.yaml
apiVersion: v1
kind: Service
metadata:
name: elastic-webhook-server
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
spec:
ports:
- name: https
port: 443
targetPort: 9443
selector:
control-plane: elastic-operator
---
# Source: eck-operator/templates/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elastic-operator
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
spec:
selector:
matchLabels:
control-plane: elastic-operator
serviceName: elastic-operator
replicas: 1
template:
metadata:
annotations:
# Rename the fields "error" to "error.message" and "source" to "event.source"
# This is to avoid a conflict with the ECS "error" and "source" documents.
"co.elastic.logs/raw": "[{\"type\":\"container\",\"json.keys_under_root\":true,\"paths\":[\"/var/log/containers/*${data.kubernetes.container.id}.log\"],\"processors\":[{\"convert\":{\"mode\":\"rename\",\"ignore_missing\":true,\"fields\":[{\"from\":\"error\",\"to\":\"_error\"}]}},{\"convert\":{\"mode\":\"rename\",\"ignore_missing\":true,\"fields\":[{\"from\":\"_error\",\"to\":\"error.message\"}]}},{\"convert\":{\"mode\":\"rename\",\"ignore_missing\":true,\"fields\":[{\"from\":\"source\",\"to\":\"_source\"}]}},{\"convert\":{\"mode\":\"rename\",\"ignore_missing\":true,\"fields\":[{\"from\":\"_source\",\"to\":\"event.source\"}]}}]}]"
"checksum/config": 882102069a9b11c3a4edfd77edcbbf9c3873f3dfc0d3f41676bd953ed4a3ce28
labels:
control-plane: elastic-operator
spec:
terminationGracePeriodSeconds: 10
serviceAccountName: elastic-operator
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
containers:
- image: "docker.elastic.co/eck/eck-operator:2.14.0"
imagePullPolicy: IfNotPresent
name: manager
args:
- "manager"
- "--config=/conf/eck.yaml"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
env:
- name: OPERATOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: WEBHOOK_SECRET
value: elastic-webhook-server-cert
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 100m
memory: 150Mi
ports:
- containerPort: 9443
name: https-webhook
protocol: TCP
volumeMounts:
- mountPath: "/conf"
name: conf
readOnly: true
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: cert
readOnly: true
volumes:
- name: conf
configMap:
name: elastic-operator
- name: cert
secret:
defaultMode: 420
secretName: elastic-webhook-server-cert
---
# Source: eck-operator/templates/webhook.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: elastic-webhook.k8s.elastic.co
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "2.14.0"
webhooks:
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-agent-k8s-elastic-co-v1alpha1-agent
failurePolicy: Ignore
name: elastic-agent-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- agent.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- agents
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-apm-k8s-elastic-co-v1-apmserver
failurePolicy: Ignore
name: elastic-apm-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- apm.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- apmservers
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-apm-k8s-elastic-co-v1beta1-apmserver
failurePolicy: Ignore
name: elastic-apm-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- apm.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- apmservers
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-beat-k8s-elastic-co-v1beta1-beat
failurePolicy: Ignore
name: elastic-beat-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- beat.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- beats
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-enterprisesearch-k8s-elastic-co-v1-enterprisesearch
failurePolicy: Ignore
name: elastic-ent-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- enterprisesearch.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- enterprisesearches
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-enterprisesearch-k8s-elastic-co-v1beta1-enterprisesearch
failurePolicy: Ignore
name: elastic-ent-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- enterprisesearch.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- enterprisesearches
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-elasticsearch-k8s-elastic-co-v1-elasticsearch
failurePolicy: Ignore
name: elastic-es-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- elasticsearch.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- elasticsearches
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-elasticsearch-k8s-elastic-co-v1beta1-elasticsearch
failurePolicy: Ignore
name: elastic-es-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- elasticsearch.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- elasticsearches
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-ems-k8s-elastic-co-v1alpha1-mapsservers
failurePolicy: Ignore
name: elastic-ems-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- maps.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- mapsservers
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-kibana-k8s-elastic-co-v1-kibana
failurePolicy: Ignore
name: elastic-kb-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- kibana.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- kibanas
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-kibana-k8s-elastic-co-v1beta1-kibana
failurePolicy: Ignore
name: elastic-kb-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- kibana.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- kibanas
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-autoscaling-k8s-elastic-co-v1alpha1-elasticsearchautoscaler
failurePolicy: Ignore
name: elastic-esa-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- autoscaling.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- elasticsearchautoscalers
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-scp-k8s-elastic-co-v1alpha1-stackconfigpolicies
failurePolicy: Ignore
name: elastic-scp-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- stackconfigpolicy.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- stackconfigpolicies
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-logstash-k8s-elastic-co-v1alpha1-logstash
failurePolicy: Ignore
name: elastic-logstash-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups:
- logstash.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- logstashes

6
flake.lock generated
View File

@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1764587062,
"narHash": "sha256-hdFa0TAVQAQLDF31cEW3enWmBP+b592OvHs6WVe3D8k=",
"lastModified": 1762943920,
"narHash": "sha256-ITeH8GBpQTw9457ICZBddQEBjlXMmilML067q0e6vqY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c1cb7d097cb250f6e1904aacd5f2ba5ffd8a49ce",
"rev": "91c9a64ce2a84e648d0cf9671274bb9c2fb9ba60",
"type": "github"
},
"original": {

View File

@@ -3,8 +3,9 @@ import { TerraformStack } from "cdktf";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { NamespaceV1 } from "@cdktf/provider-kubernetes/lib/namespace-v1";
import { OnePasswordSecret } from "../../utils";
// import { TerraFirmaGreg } from "./tfg";
// import { GTNH } from "./gtnh";
import { TerraFirmaGreg } from "./tfg";
import { GTNH } from "./gtnh";
import { StarTechnology } from "./star-technology";
export class GamingServices extends TerraformStack {
constructor(scope: Construct, id: string) {
@@ -29,7 +30,8 @@ export class GamingServices extends TerraformStack {
itemPath: "vaults/Lab/items/curseforge",
});
// new TerraFirmaGreg(this, "tfg", provider, namespace);
// new GTNH(this, "gtnh", provider, namespace);
new TerraFirmaGreg(this, "tfg", provider, namespace);
new GTNH(this, "gtnh", provider, namespace);
new StarTechnology(this, "star-technology", provider, namespace);
}
}

View File

@@ -0,0 +1,74 @@
import { Construct } from "constructs";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { MinecraftServer } from "./utils";
export class StarTechnology extends Construct {
constructor(
scope: Construct,
id: string,
provider: KubernetesProvider,
namespace: string,
) {
super(scope, id);
new MinecraftServer(this, "star-technology", {
provider,
namespace,
image: "itzg/minecraft-server:java21",
name: "star-technology",
env: [
{
name: "EULA",
value: "TRUE",
},
{
name: "MODE",
value: "survival",
},
{
name: "MODPACK_PLATFORM",
value: "AUTO_CURSEFORGE",
},
{
name: "CF_API_KEY",
valueFrom: {
secretKeyRef: {
name: "curseforge",
key: "credential",
},
},
},
{
name: "CF_PAGE_URL",
value:
"https://www.curseforge.com/minecraft/modpacks/star-technology",
},
{
name: "VERSION",
value: "1.20.1",
},
{
name: "INIT_MEMORY",
value: "2G",
},
{
name: "MAX_MEMORY",
value: "12G",
},
{
name: "ALLOW_FLIGHT",
value: "TRUE",
},
{
name: "ENABLE_ROLLING_LOGS",
value: "TRUE",
},
{
name: "USE_MEOWICE_FLAGS",
value: "TRUE",
},
],
});
}
}

View File

@@ -46,7 +46,7 @@ export class TerraFirmaGreg extends Construct {
},
{
name: "CF_FILENAME_MATCHER",
value: "0.11.8",
value: "0.10.17",
},
{
name: "VERSION",

View File

@@ -53,7 +53,7 @@ export class MinecraftServer extends Construct {
},
waitForRollout: false,
spec: {
replicas: "0",
replicas: "1",
serviceName: name,
updateStrategy: [
{
@@ -75,6 +75,10 @@ export class MinecraftServer extends Construct {
{
metadata: {
name: `${name}-data`,
labels: {
"recurring-job.longhorn.io/source": "enabled",
"recurring-job.longhorn.io/daily-backup": "enabled",
},
},
spec: {
accessModes: ["ReadWriteOnce"],

View File

@@ -42,14 +42,5 @@ export class K8SOperators extends TerraformStack {
});
barman.node.addDependency(cnpg);
new Release(this, "elasticsearch", {
provider: helm,
repository: "https://helm.elastic.co",
chart: "eck-operator",
name: "elasticsearch",
namespace: "elastic-system",
createNamespace: true,
});
}
}

View File

@@ -9,7 +9,6 @@ import { NetworkSecurity } from "./network-security";
import { GamingServices } from "./gaming-services/minecraft";
import { MediaServices } from "./media-services";
import { PKI } from "./pki";
import { Netbird } from "./netbird";
dotenv.config();
@@ -47,9 +46,6 @@ mediaServices.node.addDependency(networkSecurity);
const caches = new CacheInfrastructure(app, "cache-infrastructure");
caches.node.addDependency(utilityServices);
const netbird = new Netbird(app, "netbird");
netbird.node.addDependency(utilityServices);
const deploy: (stack: TerraformStack, key: string) => S3Backend = (
stack,
key,
@@ -79,6 +75,5 @@ deploy(utilityServices, "utility-services");
deploy(caches, "cache-infrastructure");
deploy(gamingServices, "gaming-services");
deploy(mediaServices, "media-services");
deploy(netbird, "netbird");
app.synth();

View File

@@ -3,7 +3,7 @@ import { TerraformStack } from "cdktf";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { NamespaceV1 } from "@cdktf/provider-kubernetes/lib/namespace-v1";
import { CloudflareCertificate, LonghornPvc } from "../utils";
import { LonghornPvc } from "../utils";
import { JellyfinServer } from "./jellyfin";
import { SonarrServer } from "./sonarr";
import { RadarrServer } from "./radarr";
@@ -42,28 +42,10 @@ export class MediaServices extends TerraformStack {
size: "450Gi",
});
const certificateSecretName = "media-services-tls";
new CloudflareCertificate(this, "cloudflare-certificate", {
provider,
namespace,
name: "media-services",
dnsNames: [
"media.dogar.dev",
"sonarr.dogar.dev",
"radarr.dogar.dev",
"torrent.dogar.dev",
"prowlarr.dogar.dev",
],
secretName: certificateSecretName,
commonName: "media.dogar.dev",
});
// Deploy media services
new JellyfinServer(this, "jellyfin", {
provider,
namespace,
certificateSecretName,
mediaPvcName: mediaPvc.name,
host: "media.dogar.dev",
});
@@ -71,7 +53,6 @@ export class MediaServices extends TerraformStack {
new SonarrServer(this, "sonarr", {
provider,
namespace,
certificateSecretName,
mediaPvcName: mediaPvc.name,
downloadsPvcName: downloadsPvc.name,
host: "sonarr.dogar.dev",
@@ -80,7 +61,6 @@ export class MediaServices extends TerraformStack {
new RadarrServer(this, "radarr", {
provider,
namespace,
certificateSecretName,
mediaPvcName: mediaPvc.name,
downloadsPvcName: downloadsPvc.name,
host: "radarr.dogar.dev",
@@ -89,7 +69,6 @@ export class MediaServices extends TerraformStack {
new QBittorrentServer(this, "qbittorrent", {
provider,
namespace,
certificateSecretName,
downloadsPvcName: downloadsPvc.name,
host: "torrent.dogar.dev",
});
@@ -97,8 +76,6 @@ export class MediaServices extends TerraformStack {
new ProwlarrServer(this, "prowlarr", {
provider,
namespace,
certificateSecretName,
host: "prowlarr.dogar.dev",
});
}
}

View File

@@ -10,8 +10,6 @@ type JellyfinServerOptions = BaseMediaServiceOptions & {
mediaPvcName: string;
/** Hostname for the ingress */
host: string;
/** Secret name for the TLS certificate */
certificateSecretName: string;
};
export class JellyfinServer extends Construct {
@@ -53,6 +51,7 @@ export class JellyfinServer extends Construct {
targetPort: "discovery",
},
],
type: "ClusterIP",
},
});
@@ -146,7 +145,6 @@ export class JellyfinServer extends Construct {
host,
serviceName: name,
servicePort: 80,
tlsSecretName: options.certificateSecretName,
});
}
}

View File

@@ -2,25 +2,18 @@ import { Construct } from "constructs";
import { DeploymentV1 } from "@cdktf/provider-kubernetes/lib/deployment-v1";
import { ServiceV1 } from "@cdktf/provider-kubernetes/lib/service-v1";
import { InternalIngressRoute, LonghornPvc } from "../../utils";
import { LonghornPvc } from "../../utils";
import {
BaseMediaServiceOptions,
getWorkerNodeSelector,
getCommonEnv,
} from "../types";
type ProwlarrOptions = BaseMediaServiceOptions & {
/** Hostname for the ingress */
host: string;
/** Secret name for the TLS certificate */
certificateSecretName: string;
};
export class ProwlarrServer extends Construct {
constructor(scope: Construct, id: string, options: ProwlarrOptions) {
constructor(scope: Construct, id: string, options: BaseMediaServiceOptions) {
super(scope, id);
const { provider, namespace, host } = options;
const { provider, namespace } = options;
const name = "prowlarr";
// Config PVC with backup
@@ -109,15 +102,6 @@ export class ProwlarrServer extends Construct {
},
});
// Ingress
new InternalIngressRoute(this, "ingress", {
provider,
namespace,
name,
host,
serviceName: name,
servicePort: 80,
tlsSecretName: options.certificateSecretName,
});
// Note: No ingress - Prowlarr is for internal use only
}
}

View File

@@ -14,12 +14,14 @@ type QBittorrentServerOptions = BaseMediaServiceOptions & {
downloadsPvcName: string;
/** Hostname for the ingress */
host: string;
/** Secret name for the TLS certificate */
certificateSecretName: string;
};
export class QBittorrentServer extends Construct {
constructor(scope: Construct, id: string, options: QBittorrentServerOptions) {
constructor(
scope: Construct,
id: string,
options: QBittorrentServerOptions,
) {
super(scope, id);
const { provider, namespace, downloadsPvcName, host } = options;
@@ -143,7 +145,6 @@ export class QBittorrentServer extends Construct {
host,
serviceName: name,
servicePort: 80,
tlsSecretName: options.certificateSecretName,
});
}
}

View File

@@ -16,8 +16,6 @@ type RadarrServerOptions = BaseMediaServiceOptions & {
downloadsPvcName: string;
/** Hostname for the ingress */
host: string;
/** Secret name for the TLS certificate */
certificateSecretName: string;
};
export class RadarrServer extends Construct {
@@ -142,7 +140,6 @@ export class RadarrServer extends Construct {
host,
serviceName: name,
servicePort: 80,
tlsSecretName: options.certificateSecretName,
});
}
}

View File

@@ -16,8 +16,6 @@ type SonarrServerOptions = BaseMediaServiceOptions & {
downloadsPvcName: string;
/** Hostname for the ingress */
host: string;
/** Secret name for the TLS certificate */
certificateSecretName: string;
};
export class SonarrServer extends Construct {
@@ -142,7 +140,6 @@ export class SonarrServer extends Construct {
host,
serviceName: name,
servicePort: 80,
tlsSecretName: options.certificateSecretName,
});
}
}

View File

@@ -1,162 +0,0 @@
import * as fs from "fs";
import * as path from "path";
import { Construct } from "constructs";
import { TerraformStack } from "cdktf";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { NamespaceV1 } from "@cdktf/provider-kubernetes/lib/namespace-v1";
import { DataKubernetesSecretV1 } from "@cdktf/provider-kubernetes/lib/data-kubernetes-secret-v1";
import { HelmProvider } from "@cdktf/provider-helm/lib/provider";
import { SecretV1 } from "@cdktf/provider-kubernetes/lib/secret-v1";
import { Release } from "@cdktf/provider-helm/lib/release";
import { CloudflareCertificate, OnePasswordSecret } from "../utils";
import { DeploymentV1 } from "@cdktf/provider-kubernetes/lib/deployment-v1";
export class Netbird extends TerraformStack {
constructor(scope: Construct, id: string) {
super(scope, id);
const kubernetes = new KubernetesProvider(this, "kubernetes", {
configPath: "~/.kube/config",
});
const helm = new HelmProvider(this, "helm", {
kubernetes: {
configPath: "~/.kube/config",
},
});
const namespace = "netbird";
// Create namespace
new NamespaceV1(this, "namespace", {
metadata: {
name: namespace,
},
});
new OnePasswordSecret(this, "netbird-secret", {
name: "netbird",
namespace,
provider: kubernetes,
itemPath: "vaults/Lab/items/Netbird",
});
const pgClientCert = new DataKubernetesSecretV1(
this,
"netbird-client-cert",
{
provider: kubernetes,
metadata: {
name: "netbird-client-cert",
namespace: "homelab",
},
},
);
const pgCaCert = new DataKubernetesSecretV1(this, "postgres-ca-cert", {
provider: kubernetes,
metadata: {
name: "postgres-server-cert",
namespace: "homelab",
},
});
const pgSslBundle = new SecretV1(this, "netbird-postgres-ssl", {
provider: kubernetes,
metadata: {
name: "netbird-postgres-ssl-bundle",
namespace,
},
data: {
"tls.crt": pgClientCert.data.lookup("tls.crt"),
"tls.key": pgClientCert.data.lookup("tls.key"),
"ca.crt": pgCaCert.data.lookup("ca.crt"),
},
});
new CloudflareCertificate(this, "netbird-cloudflare-cert", {
provider: kubernetes,
name: "netbird",
namespace,
dnsNames: ["vpn.dogar.dev"],
secretName: "netbird-tls",
});
new Release(this, "netbird", {
dependsOn: [pgSslBundle],
provider: helm,
namespace,
createNamespace: true,
name: "netbird",
repository: "https://netbirdio.github.io/helms",
chart: "netbird",
values: [fs.readFileSync(path.join(__dirname, "values.yaml"), "utf8")],
}).importFrom("netbird/netbird");
new OnePasswordSecret(this, "netbird-setup-key", {
name: "netbird-setup-key",
namespace,
provider: kubernetes,
itemPath: "vaults/Lab/items/netbird-setup-key",
});
new DeploymentV1(this, "netbird-routing-peers", {
provider: kubernetes,
metadata: {
name: "netbird-routing-peer",
namespace,
},
spec: {
replicas: "3",
selector: {
matchLabels: {
app: "netbird-routing-peers",
},
},
template: {
metadata: {
labels: {
app: "netbird-routing-peers",
},
},
spec: {
container: [
{
name: "netbird-routing-peers",
image: "netbirdio/netbird:latest",
env: [
{
name: "NB_SETUP_KEY",
valueFrom: {
secretKeyRef: {
name: "netbird-setup-key",
key: "credential",
},
},
},
{
name: "NB_MANAGEMENT_URL",
value: "https://vpn.dogar.dev",
},
{
name: "NB_HOSTNAME",
value: "netbird-k8s-router",
},
{
name: "NB_LOG_LEVEL",
value: "info",
},
],
securityContext: {
capabilities: {
add: ["NET_ADMIN", "SYS_RESOURCE", "SYS_ADMIN"],
},
},
},
],
},
},
},
});
}
}

View File

@@ -1,226 +0,0 @@
fullnameOverride: netbird
management:
image:
tag: latest
configmap: |-
{
"Stuns": [
{
"Proto": "udp",
"URI": "{{ .STUN_SERVER }}",
"Username": "",
"Password": ""
}
],
"TURNConfig": {
"TimeBasedCredentials": false,
"CredentialsTTL": "12h0m0s",
"Secret": "secret",
"Turns": [
{
"Proto": "udp",
"URI": "{{ .TURN_SERVER }}",
"Username": "{{ .TURN_SERVER_USER }}",
"Password": "{{ .TURN_SERVER_PASSWORD }}"
}
]
},
"Relay": {
"Addresses": ["rels://vpn.dogar.dev:443/relay"],
"CredentialsTTL": "24h",
"Secret": "{{ .RELAY_PASSWORD }}"
},
"Signal": {
"Proto": "https",
"URI": "vpn.dogar.dev:443",
"Username": "",
"Password": ""
},
"Datadir": "/var/lib/netbird/",
"DataStoreEncryptionKey": "{{ .DATASTORE_ENCRYPTION_KEY }}",
"HttpConfig": {
"LetsEncryptDomain": "",
"CertFile": "",
"CertKey": "",
"AuthAudience": "{{ .IDP_CLIENT_ID }}",
"AuthIssuer": "https://auth.dogar.dev/application/o/netbird/",
"AuthUserIDClaim": "",
"AuthKeysLocation": "https://auth.dogar.dev/application/o/netbird/jwks/",
"OIDCConfigEndpoint": "https://auth.dogar.dev/application/o/netbird/.well-known/openid-configuration",
"IdpSignKeyRefreshEnabled": false
},
"IdpManagerConfig": {
"ManagerType": "authentik",
"ClientConfig": {
"Issuer": "https://auth.dogar.dev/application/o/netbird",
"TokenEndpoint": "https://auth.dogar.dev/application/o/token/",
"ClientID": "{{ .IDP_CLIENT_ID }}",
"ClientSecret": "",
"GrantType": "client_credentials"
},
"ExtraConfig": {
"Password": "{{ .IDP_SERVICE_ACCOUNT_PASSWORD }}",
"Username": "{{ .IDP_SERVICE_ACCOUNT_USER }}"
},
"Auth0ClientCredentials": null,
"AzureClientCredentials": null,
"KeycloakClientCredentials": null,
"ZitadelClientCredentials": null
},
"DeviceAuthorizationFlow": {
"Provider": "hosted",
"ProviderConfig": {
"ClientID": "{{ .IDP_CLIENT_ID }}",
"ClientSecret": "",
"Domain": "auth.dogar.dev",
"Audience": "{{ .IDP_CLIENT_ID }}",
"TokenEndpoint": "https://auth.dogar.dev/application/o/token/",
"DeviceAuthEndpoint": "https://auth.dogar.dev/application/o/device/",
"AuthorizationEndpoint": "",
"Scope": "openid",
"UseIDToken": false,
"RedirectURLs": null
}
},
"PKCEAuthorizationFlow": {
"ProviderConfig": {
"ClientID": "{{ .IDP_CLIENT_ID }}",
"ClientSecret": "",
"Domain": "",
"Audience": "{{ .IDP_CLIENT_ID }}",
"TokenEndpoint": "https://auth.dogar.dev/application/o/token/",
"DeviceAuthEndpoint": "",
"AuthorizationEndpoint": "https://auth.dogar.dev/application/o/authorize/",
"Scope": "openid profile email offline_access api",
"UseIDToken": false,
"RedirectURLs": ["http://localhost:53000"]
}
},
"StoreConfig": {
"Engine": "postgres"
},
"ReverseProxy": {
"TrustedHTTPProxies": null,
"TrustedHTTPProxiesCount": 0,
"TrustedPeers": null
}
}
persistentVolume:
enabled: true
storageClass: longhorn
size: 1Gi
envFromSecret:
NETBIRD_STORE_ENGINE_POSTGRES_DSN: netbird/postgresDSN
STUN_SERVER: netbird/stunServer
TURN_SERVER: netbird/turnServer
TURN_SERVER_USER: netbird/turnServerUser
TURN_SERVER_PASSWORD: netbird/turnServerPassword
RELAY_PASSWORD: netbird/relayPassword
IDP_CLIENT_ID: netbird/idpClientID
IDP_SERVICE_ACCOUNT_USER: netbird/idpServiceAccountUser
IDP_SERVICE_ACCOUNT_PASSWORD: netbird/idpServiceAccountPassword
DATASTORE_ENCRYPTION_KEY: netbird/datastoreEncryptionKey
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 180
periodSeconds: 10
timeoutSeconds: 3
tcpSocket:
port: http
volumes:
- name: postgres-ssl-bundle
secret:
secretName: netbird-postgres-ssl-bundle
volumeMounts:
- name: postgres-ssl-bundle
mountPath: /etc/ssl/certs/postgres-ssl-bundle
readOnly: true
signal:
enabled: true
image:
tag: latest
relay:
image:
tag: latest
envFromSecret:
NB_AUTH_SECRET: netbird/relayPassword
env:
NB_LOG_LEVEL: info
NB_LISTEN_ADDRESS: ":33080"
NB_EXPOSED_ADDRESS: rels://vpn.dogar.dev:443/relay
dashboard:
enabled: true
image:
tag: "v2.23.0"
env:
# Endpoints
NETBIRD_MGMT_API_ENDPOINT: https://vpn.dogar.dev:443
NETBIRD_MGMT_GRPC_API_ENDPOINT: https://vpn.dogar.dev:443
# OIDC
AUTH_CLIENT_SECRET:
AUTH_AUTHORITY: https://auth.dogar.dev/application/o/netbird/
USE_AUTH0: false
AUTH_SUPPORTED_SCOPES: openid profile email offline_access api
AUTH_REDIRECT_URI:
AUTH_SILENT_REDIRECT_URI:
NETBIRD_TOKEN_SOURCE: accessToken
NGINX_SSL_PORT:
LETSENCRYPT_DOMAIN:
LETSENCRYPT_EMAIL:
envFromSecret:
AUTH_CLIENT_ID: netbird/idpClientID
AUTH_AUDIENCE: netbird/idpClientID
extraManifests:
- apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: netbird
namespace: netbird
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`vpn.dogar.dev`) && !PathPrefix(`/api`) && !PathPrefix(`/management`) && !PathPrefix(`/signalexchange`) && !PathPrefix(`/relay`)
services:
- name: netbird-dashboard
namespace: netbird
passHostHeader: true
port: 80
- kind: Rule
match: Host(`vpn.dogar.dev`) && PathPrefix(`/api`)
services:
- name: netbird-management
namespace: netbird
passHostHeader: true
port: 80
- kind: Rule
match: Host(`vpn.dogar.dev`) && PathPrefix(`/relay`)
services:
- name: netbird-relay
namespace: netbird
passHostHeader: true
port: 33080
- kind: Rule
match: Host(`vpn.dogar.dev`) && PathPrefix(`/management`)
services:
- name: netbird-management
namespace: netbird
passHostHeader: true
port: 80
scheme: h2c
- kind: Rule
match: Host(`vpn.dogar.dev`) && PathPrefix(`/signalexchange`)
services:
- name: netbird-signal
namespace: netbird
passHostHeader: true
port: 80
scheme: h2c
tls:
secretName: netbird-tls

View File

@@ -7,10 +7,9 @@ import {
RateLimitMiddleware,
IpAllowListMiddleware,
IpAllowListMiddlewareTCP,
TLSOptions,
} from "./traefik";
import { ValkeyCluster } from "./valkey";
import { CloudflareCertificate, InternalIngressRoute } from "../utils";
import { InternalIngressRoute } from "../utils";
export class NetworkSecurity extends TerraformStack {
constructor(scope: Construct, id: string) {
@@ -68,11 +67,6 @@ export class NetworkSecurity extends TerraformStack {
name: "rate-limit",
});
new TLSOptions(this, "tls-options", {
provider: kubernetes,
namespace,
});
new IpAllowListMiddleware(this, "internal-ip-allow-list", {
provider: kubernetes,
namespace,
@@ -87,15 +81,6 @@ export class NetworkSecurity extends TerraformStack {
sourceRanges: ["192.168.18.0/24", "10.42.0.0/16"],
});
new CloudflareCertificate(this, "longhorn-cert", {
provider: kubernetes,
namespace: "longhorn-system",
name: "longhorn-ui",
dnsNames: ["longhorn.dogar.dev"],
commonName: "longhorn.dogar.dev",
secretName: "longhorn-tls",
});
new InternalIngressRoute(this, "longhorn-ui", {
provider: kubernetes,
namespace: "longhorn-system",
@@ -103,16 +88,6 @@ export class NetworkSecurity extends TerraformStack {
host: "longhorn.dogar.dev",
serviceName: "longhorn-frontend",
servicePort: 80,
tlsSecretName: "longhorn-tls",
});
new CloudflareCertificate(this, "grafana-cert", {
provider: kubernetes,
namespace: "monitoring",
name: "grafana-ui",
dnsNames: ["grafana.dogar.dev"],
commonName: "grafana.dogar.dev",
secretName: "grafana-tls",
});
new InternalIngressRoute(this, "grafana-ui", {
@@ -122,7 +97,6 @@ export class NetworkSecurity extends TerraformStack {
host: "grafana.dogar.dev",
serviceName: "prometheus-operator-grafana",
servicePort: 80,
tlsSecretName: "grafana-tls",
});
}
}

View File

@@ -1,3 +1,2 @@
export { RateLimitMiddleware } from "./rateLimit";
export { IpAllowListMiddleware, IpAllowListMiddlewareTCP } from "./ipAllowList";
export { TLSOptions } from "./tlsOpts";

View File

@@ -7,8 +7,8 @@ type RateLimitMiddlewareOptions = {
namespace: string;
name: string;
average?: number; // default 60
burst?: number; // default 120
average?: number; // default 10
burst?: number; // default 50
period?: string; // default "1s"
};
@@ -18,8 +18,8 @@ export class RateLimitMiddleware extends Construct {
constructor(scope: Construct, id: string, opts: RateLimitMiddlewareOptions) {
super(scope, id);
const average = opts.average ?? 60;
const burst = opts.burst ?? 120;
const average = opts.average ?? 10;
const burst = opts.burst ?? 50;
const period = opts.period ?? "1s";
this.ref = `${opts.namespace}/${opts.name}`;
@@ -38,6 +38,11 @@ export class RateLimitMiddleware extends Construct {
average,
burst,
period,
redis: {
endpoints: [`valkey.${opts.namespace}.svc.cluster.local:6379`],
secret: "valkey",
db: 5,
},
},
},
},

View File

@@ -1,31 +0,0 @@
import { Construct } from "constructs";
import { Manifest } from "@cdktf/provider-kubernetes/lib/manifest";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
export class TLSOptions extends Construct {
constructor(
scope: Construct,
id: string,
opts: { provider: KubernetesProvider; namespace: string },
) {
super(scope, id);
const { provider, namespace } = opts;
new Manifest(this, "traefik-tls-options", {
provider,
manifest: {
apiVersion: "traefik.io/v1alpha1",
kind: "TLSOption",
metadata: {
namespace,
name: "tls-options",
},
spec: {
minVersion: "VersionTLS13",
sniStrict: true,
},
},
});
}
}

View File

@@ -52,9 +52,12 @@ export class PKI extends TerraformStack {
provider: kubernetes,
namespace,
apiVersion: "cert-manager.io/v1",
rootSecretName: "root-secret",
intermediateSecretName: `${namespace}-ca-secret`,
secretName: "root-secret",
commonName: "Homelab Root CA",
privateKey: {
algorithm: "Ed25519",
size: 256,
},
});
new PublicIssuer(this, "public-issuer", {

View File

@@ -7,8 +7,11 @@ type PrivateIssuerOptions = {
namespace: string;
apiVersion: string;
commonName: string;
rootSecretName: string;
intermediateSecretName: string;
secretName: string;
privateKey: {
algorithm: "RSA" | "ECDSA" | "Ed25519";
size: number;
};
};
export class PrivateIssuer extends Construct {
@@ -18,41 +21,44 @@ export class PrivateIssuer extends Construct {
const {
provider,
namespace,
apiVersion,
commonName,
rootSecretName,
intermediateSecretName,
privateKey,
secretName,
apiVersion,
} = options;
//
// 1. Root CA (self-signed)
//
new Manifest(this, "root-ca-issuer", {
// Self-signed ClusterIssuer for initial CA
new Manifest(this, "ca-issuer", {
provider,
manifest: {
apiVersion,
kind: "ClusterIssuer",
metadata: { name: "root-ca-selfsigned" },
spec: { selfSigned: {} },
metadata: {
name: "ca-issuer",
},
spec: {
selfSigned: {},
},
},
});
new Manifest(this, "root-ca", {
// Self-signed CA Certificate
new Manifest(this, "selfsigned-ca", {
provider,
manifest: {
apiVersion,
kind: "Certificate",
metadata: { name: "root-ca", namespace },
metadata: {
name: "selfsigned-ca",
namespace,
},
spec: {
isCA: true,
commonName: `${commonName} Root CA`,
secretName: rootSecretName,
privateKey: {
algorithm: "RSA",
size: 4096,
},
commonName,
secretName,
privateKey,
issuerRef: {
name: "root-ca-selfsigned",
name: "ca-issuer",
kind: "ClusterIssuer",
group: "cert-manager.io",
},
@@ -60,55 +66,19 @@ export class PrivateIssuer extends Construct {
},
});
//
// 2. Intermediate CA (signed by root CA)
//
new Manifest(this, "intermediate-ca-issuer", {
provider,
manifest: {
apiVersion,
kind: "ClusterIssuer",
metadata: { name: "root-ca-signer" },
spec: {
ca: { secretName: rootSecretName },
},
},
});
new Manifest(this, "intermediate-ca", {
provider,
manifest: {
apiVersion,
kind: "Certificate",
metadata: { name: "intermediate-ca", namespace },
spec: {
isCA: true,
commonName: `${commonName} Intermediate CA`,
secretName: intermediateSecretName,
privateKey: {
algorithm: "ECDSA",
size: 384,
},
issuerRef: {
name: "root-ca-signer",
kind: "ClusterIssuer",
group: "cert-manager.io",
},
},
},
});
//
// 3. Final public cluster issuer (used by your apps)
//
// CA-based ClusterIssuer
new Manifest(this, "cluster-issuer", {
provider,
manifest: {
apiVersion,
kind: "ClusterIssuer",
metadata: { name: "cluster-issuer" },
metadata: {
name: "cluster-issuer",
},
spec: {
ca: { secretName: intermediateSecretName },
ca: {
secretName,
},
},
},
});

View File

@@ -79,7 +79,7 @@ export class GiteaServer extends Construct {
match: "HostSNI(`*`)",
entryPoint: "ssh",
serviceName: `${name}-ssh`,
servicePort: 2222,
servicePort: 22,
});
new PublicIngressRoute(this, "http-ingress", {

View File

@@ -12,7 +12,6 @@ service:
ssh:
annotations:
metallb.universe.tf/allow-shared-ip: gitea
port: 2222
ingress:
enabled: false
gitea:
@@ -41,7 +40,7 @@ gitea:
SSH_DOMAIN: git.dogar.dev
DISABLE_SSH: false
SSH_LISTEN_PORT: 2222
SSH_PORT: 2222
SSH_PORT: 22
database:
DB_TYPE: postgres
HOST: postgres-cluster-rw
@@ -180,7 +179,7 @@ extraVolumes:
path: root.crt
- name: gitea-tls-internal
secret:
secretName: gitea-http-tls-internal
secretName: gitea-tls-internal
- name: gitea-temp
emptyDir: {}
extraInitVolumeMounts:

View File

@@ -8,7 +8,6 @@ import { GiteaRunner, GiteaServer } from "./gitea";
import { AuthentikServer } from "./authentik";
import { PostgresCluster } from "./postgres";
import { DynamicDNS } from "./dynamic-dns";
import { PublicIngressRoute } from "../utils";
export class UtilityServices extends TerraformStack {
constructor(scope: Construct, id: string) {
@@ -71,9 +70,6 @@ export class UtilityServices extends TerraformStack {
"nix.dogar.dev",
"pip.dogar.dev",
"npm.dogar.dev",
"go.dogar.dev",
"elastic.dogar.dev",
"kibana.dogar.dev",
],
});
@@ -82,7 +78,7 @@ export class UtilityServices extends TerraformStack {
name: "postgres-cluster",
namespace,
provider: kubernetes,
users: ["shahab", "budget-tracker", "authentik", "gitea", "netbird"],
users: ["shahab", "budget-tracker", "authentik", "gitea"],
primaryUser: "shahab",
initSecretName: "postgres-password",
backupR2EndpointURL: `https://${r2Endpoint}`,
@@ -117,25 +113,5 @@ export class UtilityServices extends TerraformStack {
name: "gitea-runner",
replicas: 3,
});
new PublicIngressRoute(this, "elasticsearch", {
provider: kubernetes,
namespace: "elastic-system",
name: "elasticsearch",
host: "elastic.dogar.dev",
serviceName: "elasticsearch-es-http",
servicePort: 9200,
serviceProtocol: "https",
});
new PublicIngressRoute(this, "kibana", {
provider: kubernetes,
namespace: "elastic-system",
name: "kibana",
host: "kibana.dogar.dev",
serviceName: "kibana-kb-http",
servicePort: 5601,
serviceProtocol: "https",
});
}
}

View File

@@ -310,7 +310,6 @@ export class PostgresCluster extends Construct {
minSyncReplicas: 1,
maxSyncReplicas: 2,
primaryUpdateStrategy: "unsupervised",
enablePDB: true,
certificates: {
serverCASecret: certNames.server,
serverTLSSecret: certNames.server,
@@ -358,7 +357,6 @@ export class PostgresCluster extends Construct {
{
name: "barman-cloud.cloudnative-pg.io",
isWALArchiver: true,
enabled: true,
parameters: {
barmanObjectName: barmanStoreName,
serverName: backupServerName,

View File

@@ -19,7 +19,7 @@ export class CloudflareCertificate extends Certificate {
constructor(
scope: Construct,
id: string,
opts: Omit<CertificateOptions, "issuerRef" | "privateKey">,
opts: Omit<CertificateOptions, "issuerRef">,
) {
super(scope, id, {
...opts,
@@ -27,10 +27,6 @@ export class CloudflareCertificate extends Certificate {
name: "cloudflare-issuer",
kind: "ClusterIssuer",
},
privateKey: {
algorithm: "RSA",
size: 4096,
},
});
}
}

View File

@@ -23,7 +23,7 @@ export class PrivateCertificate extends Certificate {
constructor(
scope: Construct,
id: string,
opts: Omit<CertificateOptions, "issuerRef" | "privateKey">,
opts: Omit<CertificateOptions, "issuerRef">,
) {
super(scope, id, {
...opts,
@@ -31,11 +31,6 @@ export class PrivateCertificate extends Certificate {
name: "cluster-issuer", // internal CA
kind: "ClusterIssuer",
},
privateKey: {
algorithm: "ECDSA",
size: 384,
},
usages: ["digital signature", "key encipherment", "server auth"],
});
}
}

View File

@@ -2,7 +2,7 @@ import { Construct } from "constructs";
import { Manifest } from "@cdktf/provider-kubernetes/lib/manifest";
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
import { PrivateCertificate } from "../../cert-manager";
import { CloudflareCertificate, PrivateCertificate } from "../../cert-manager";
export type IngressRouteOptions = {
provider: KubernetesProvider;
@@ -83,7 +83,6 @@ export class IngressRoute extends Construct {
kind: "Rule",
services: [
{
namespace,
name: opts.serviceName,
port: opts.servicePort,
scheme: opts.serviceProtocol ?? "http",
@@ -110,11 +109,15 @@ export class IngressRoute extends Construct {
if (opts.tlsSecretName) {
spec.tls = {
secretName: opts.tlsSecretName,
options: {
name: "tls-options",
namespace: "homelab",
},
};
new CloudflareCertificate(this, `${name}-cert`, {
provider,
namespace,
name: opts.host,
secretName: opts.tlsSecretName,
dnsNames: [opts.host],
});
}
this.manifest = new Manifest(this, name, {

View File

@@ -1,16 +1,63 @@
import { Construct } from "constructs";
import { IngressRoute, IngressRouteOptions } from "./ingress";
import { DataTerraformRemoteStateS3 } from "cdktf";
import { DataKubernetesNamespaceV1 } from "@cdktf/provider-kubernetes/lib/data-kubernetes-namespace-v1";
export class InternalIngressRoute extends IngressRoute {
constructor(
scope: Construct,
id: string,
opts: Omit<IngressRouteOptions, "entryPoints" | "middlewares">,
) {
super(scope, id, {
...opts,
type InternalIngressRouteOptions = Omit<
IngressRouteOptions,
"entryPoints" | "tlsSecretName" | "middlewares"
>;
export class InternalIngressRoute extends Construct {
constructor(scope: Construct, id: string, opts: InternalIngressRouteOptions) {
super(scope, id);
const r2Endpoint = `${process.env.ACCOUNT_ID!}.r2.cloudflarestorage.com`;
const coreServicesState = new DataTerraformRemoteStateS3(
this,
"core-services-state",
{
usePathStyle: true,
skipRegionValidation: true,
skipCredentialsValidation: true,
skipRequestingAccountId: true,
skipS3Checksum: true,
encrypt: true,
bucket: "terraform-state",
key: "core-services/terraform.tfstate",
endpoints: {
s3: `https://${r2Endpoint}`,
},
region: "auto",
accessKey: process.env.ACCESS_KEY,
secretKey: process.env.SECRET_KEY,
},
);
const namespaceName = coreServicesState.getString("namespace-output");
const namespaceResource = new DataKubernetesNamespaceV1(
this,
"core-services-namespace",
{
provider: opts.provider,
metadata: {
name: namespaceName,
},
},
);
const namespace = namespaceResource.metadata.name;
new IngressRoute(this, opts.name, {
provider: opts.provider,
namespace: opts.namespace,
host: opts.host,
path: opts.path ?? "/",
serviceName: opts.serviceName,
servicePort: opts.servicePort,
entryPoints: ["websecure"],
middlewares: ["homelab/ip-allow-list"],
tlsSecretName: `${opts.name}-tls`,
middlewares: [`${namespace}/ip-allow-list`],
name: opts.name,
});
}
}

View File

@@ -1,33 +1,64 @@
import { Construct } from "constructs";
import { IngressRoute, IngressRouteOptions } from "./ingress";
import { CloudflareCertificate } from "../../cert-manager";
import { DataTerraformRemoteStateS3 } from "cdktf";
import { DataKubernetesNamespaceV1 } from "@cdktf/provider-kubernetes/lib/data-kubernetes-namespace-v1";
export class PublicIngressRoute extends IngressRoute {
constructor(
scope: Construct,
id: string,
opts: Omit<
type PublicIngressRouteOptions = Omit<
IngressRouteOptions,
"entryPoints" | "tlsSecretName" | "middlewares"
>,
) {
const tlsSecretName = `${opts.name}-tls`;
>;
super(scope, id, {
...opts,
tlsSecretName,
export class PublicIngressRoute extends Construct {
constructor(scope: Construct, id: string, opts: PublicIngressRouteOptions) {
super(scope, id);
const r2Endpoint = `${process.env.ACCOUNT_ID!}.r2.cloudflarestorage.com`;
const coreServicesState = new DataTerraformRemoteStateS3(
this,
"core-services-state",
{
usePathStyle: true,
skipRegionValidation: true,
skipCredentialsValidation: true,
skipRequestingAccountId: true,
skipS3Checksum: true,
encrypt: true,
bucket: "terraform-state",
key: "core-services/terraform.tfstate",
endpoints: {
s3: `https://${r2Endpoint}`,
},
region: "auto",
accessKey: process.env.ACCESS_KEY,
secretKey: process.env.SECRET_KEY,
},
);
const namespaceName = coreServicesState.getString("namespace-output");
const namespaceResource = new DataKubernetesNamespaceV1(
this,
"core-services-namespace",
{
provider: opts.provider,
metadata: {
name: namespaceName,
},
},
);
const namespace = namespaceResource.metadata.name;
new IngressRoute(this, opts.name, {
provider: opts.provider,
namespace: opts.namespace,
host: opts.host,
path: opts.path ?? "/",
serviceName: opts.serviceName,
servicePort: opts.servicePort,
serviceProtocol: opts.serviceProtocol,
entryPoints: ["websecure"],
middlewares: ["homelab/rate-limit"],
});
const { provider, name, namespace, host } = opts;
new CloudflareCertificate(this, `${name}-cert`, {
provider,
namespace,
name: host,
secretName: tlsSecretName,
dnsNames: [host],
tlsSecretName: `${opts.name}-tls`,
middlewares: [`${namespace}/rate-limit`],
name: opts.name,
});
}
}