diff --git a/apps/gramo/datas.tf b/apps/gramo/datas.tf new file mode 100644 index 0000000..856efae --- /dev/null +++ b/apps/gramo/datas.tf @@ -0,0 +1,24 @@ +locals { + common-labels = { + "vynil.solidite.fr/owner-name" = var.instance + "vynil.solidite.fr/owner-namespace" = var.namespace + "vynil.solidite.fr/owner-category" = var.category + "vynil.solidite.fr/owner-component" = var.component + "app.kubernetes.io/managed-by" = "vynil" + "app.kubernetes.io/name" = var.component + "app.kubernetes.io/instance" = var.instance + } +} + +data "kubernetes_secret_v1" "authentik" { + metadata { + name = "authentik" + namespace = "${var.domain}-auth" + } +} + +data "kustomization_overlay" "data" { + namespace = var.namespace + common_labels = local.common-labels + resources = [] +} diff --git a/apps/gramo/deploy.tf b/apps/gramo/deploy.tf new file mode 100644 index 0000000..82d1ffc --- /dev/null +++ b/apps/gramo/deploy.tf @@ -0,0 +1,59 @@ +resource "kubectl_manifest" "deploy" { + yaml_body = <<-EOF + apiVersion: apps/v1 + kind: Deployment + metadata: + name: "${var.component}-${var.instance}" + namespace: "${var.namespace}" + labels: ${jsonencode(local.common-labels)} + spec: + replicas: 1 + selector: + matchLabels: ${jsonencode(local.common-labels)} + template: + metadata: + labels: ${jsonencode(local.common-labels)} + spec: + securityContext: + fsGroup: 1000 + runAsUser: 1000 + runAsGroup: 1000 + containers: + - name: gramo + securityContext: + fsGroup: 1000 + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + env: + - name: BRIDGE_USER_AUTH + value: disabled + image: "${var.images.gramo.registry}/${var.images.gramo.repository}:${var.images.gramo.tag}" + imagePullPolicy: "${var.images.gramo.pullPolicy}" + ports: + - containerPort: 9000 + name: http + protocol: TCP + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: http + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: http + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + restartPolicy: Always + serviceAccount: "${var.component}-${var.instance}" + serviceAccountName: "${var.component}-${var.instance}" + EOF +} diff --git a/apps/gramo/index.yaml b/apps/gramo/index.yaml new file mode 100644 index 0000000..8556273 --- /dev/null +++ b/apps/gramo/index.yaml @@ -0,0 +1,108 @@ +--- +apiVersion: vinyl.solidite.fr/v1beta1 +kind: Component +category: apps +metadata: + name: gramo + description: null +options: + issuer: + default: letsencrypt-prod + examples: + - letsencrypt-prod + type: string + ingress-class: + default: traefik + examples: + - traefik + type: string + cluster-admin: + default: false + examples: + - false + type: boolean + namespaces: + default: [] + items: + type: string + type: array + domain: + default: your-company + examples: + - your-company + type: string + images: + default: + gramo: + pullPolicy: IfNotPresent + registry: docker.io + repository: sebt3/gramo + tag: 0.0.2 + examples: + - gramo: + pullPolicy: IfNotPresent + registry: docker.io + repository: sebt3/gramo + tag: 0.0.2 + properties: + gramo: + default: + pullPolicy: IfNotPresent + registry: docker.io + repository: sebt3/gramo + tag: 0.0.2 + properties: + pullPolicy: + default: IfNotPresent + enum: + - Always + - Never + - IfNotPresent + type: string + registry: + default: docker.io + type: string + repository: + default: sebt3/gramo + type: string + tag: + default: 0.0.2 + type: string + type: object + type: object + sub-domain: + default: gramo + examples: + - gramo + type: string + managed: + default: false + examples: + - false + type: boolean + app-group: + default: infra + examples: + - infra + type: string + domain-name: + default: your_company.com + examples: + - your_company.com + type: string +dependencies: +- dist: null + category: share + component: authentik-forward +- dist: null + category: core + component: secret-generator +providers: + kubernetes: true + authentik: true + kubectl: true + postgresql: null + restapi: true + http: true + gitea: null +tfaddtype: null diff --git a/apps/gramo/presentation.tf b/apps/gramo/presentation.tf new file mode 100644 index 0000000..579b92a --- /dev/null +++ b/apps/gramo/presentation.tf @@ -0,0 +1,88 @@ +locals { + dns-name = "${var.sub-domain}.${var.domain-name}" + dns-names = [local.dns-name] + app-name = var.component == var.instance ? var.instance : format("%s-%s", var.component, var.instance) + icon = "static/assets/gramo-logo.svg" + request_headers = { + "Content-Type" = "application/json" + Authorization = "Bearer ${data.kubernetes_secret_v1.authentik.data["AUTHENTIK_BOOTSTRAP_TOKEN"]}" + } + service = { + "name" = "${var.component}-${var.instance}" + "port" = { + "number" = 80 + } + } +} + +module "service" { + source = "/dist/modules/service" + component = var.component + instance = var.instance + namespace = var.namespace + labels = local.common-labels + target = "http" + port = local.service.port.number + providers = { + kubectl = kubectl + } +} + +module "ingress" { + source = "/dist/modules/ingress" + component = "" + instance = var.instance + namespace = var.namespace + issuer = var.issuer + ingress-class = var.ingress-class + labels = local.common-labels + dns-names = local.dns-names + middlewares = ["forward-${local.app-name}"] + service = local.service + providers = { + kubectl = kubectl + } +} + +module "application" { + source = "/dist/modules/application" + component = var.component + instance = var.instance + app-group = var.app-group + dns-name = local.dns-name + icon = local.icon + protocol_provider = module.forward.provider-id + providers = { + authentik = authentik + } +} + +provider "restapi" { + uri = "http://authentik.${var.domain}-auth.svc/api/v3/" + headers = local.request_headers + create_method = "PATCH" + update_method = "PATCH" + destroy_method = "PATCH" + write_returns_object = true + id_attribute = "name" +} + +module "forward" { + source = "/dist/modules/forward" + component = var.component + instance = var.instance + domain = var.domain + namespace = var.namespace + ingress-class = var.ingress-class + labels = local.common-labels + dns-names = local.dns-names + service = local.service + icon = local.icon + request_headers = local.request_headers + providers = { + restapi = restapi + http = http + kubectl = kubectl + authentik = authentik + } +} diff --git a/apps/gramo/rbac.tf b/apps/gramo/rbac.tf new file mode 100644 index 0000000..9f63bec --- /dev/null +++ b/apps/gramo/rbac.tf @@ -0,0 +1,107 @@ +locals { + sorted-namespaces = reverse(distinct(sort(var.namespaces))) +} +resource "kubectl_manifest" "gramo_sa" { + yaml_body = <<-EOF + apiVersion: v1 + kind: ServiceAccount + metadata: + name: "${var.component}-${var.instance}" + namespace: "${var.namespace}" + labels: ${jsonencode(local.common-labels)} + EOF +} + +resource "kubectl_manifest" "gramo_crb_admin" { + count = var.cluster-admin ? 1 : 0 + yaml_body = <<-EOF + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: "${var.namespace}-${var.component}-${var.instance}" + labels: ${jsonencode(local.common-labels)} + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + subjects: + - kind: ServiceAccount + name: "${var.component}-${var.instance}" + namespace: "${var.namespace}" + EOF +} + +resource "kubectl_manifest" "gramo_roles" { + count = length(local.sorted-namespaces) + yaml_body = <<-EOF + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: "${var.namespace}-${var.component}-${var.instance}" + namespace: "${local.sorted-namespaces[count.index]}" + labels: ${jsonencode(local.common-labels)} + rules: + - apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] + EOF +} + +resource "kubectl_manifest" "gramo_role_bindings" { + count = length(local.sorted-namespaces) + yaml_body = <<-EOF + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: "${var.namespace}-${var.component}-${var.instance}" + namespace: "${local.sorted-namespaces[count.index]}" + labels: ${jsonencode(local.common-labels)} + subjects: + - kind: ServiceAccount + name: "${var.component}-${var.instance}" + namespace: "${var.namespace}" + roleRef: + kind: Role + name: "${var.namespace}-${var.component}-${var.instance}" + apiGroup: rbac.authorization.k8s.io + EOF +} + +resource "kubectl_manifest" "gramo_clusterrole" { + count = length(local.sorted-namespaces)>0 ? 1 : 0 + yaml_body = <<-EOF + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: "${var.namespace}-${var.component}-${var.instance}-list" + labels: ${jsonencode(local.common-labels)} + rules: + - apiGroups: [""] + resources: ["namespaces"] + resourceNames: ${jsonencode(local.sorted-namespaces)} + verbs: ["get"] + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["list"] + EOF +} + +resource "kubectl_manifest" "gramo_clusterrole_bindings" { + count = length(local.sorted-namespaces)>0 ? 1 : 0 + yaml_body = <<-EOF + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: "${var.namespace}-${var.component}-${var.instance}-list" + namespace: "${local.sorted-namespaces[count.index]}" + labels: ${jsonencode(local.common-labels)} + subjects: + - kind: ServiceAccount + name: "${var.component}-${var.instance}" + namespace: "${var.namespace}" + roleRef: + kind: ClusterRole + name: "${var.namespace}-${var.component}-${var.instance}-list" + apiGroup: rbac.authorization.k8s.io + EOF +}