apiVersion: v1
kind: Namespace
metadata:
  name: backstage
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: backstage
  namespace: backstage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: backstage-argo-worfklows
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - workflows
    verbs:
      - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: read-all
rules:
  - apiGroups:
      - '*'
    resources:
      - '*'
    verbs:
      - get
      - list
      - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: backstage-argo-worfklows
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: backstage-argo-worfklows
subjects:
  - kind: ServiceAccount
    name: backstage
    namespace: backstage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: backstage-read-all
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: read-all
subjects:
  - kind: ServiceAccount
    name: backstage
    namespace: backstage
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: backstage-config
  namespace: backstage
data:
  app-config.yaml: |
    app:
      title: CNOE Backstage
      baseUrl: https://otc.c-one-infra.de:443
    organization:
      name: CNOE
    backend:
      # Used for enabling authentication, secret is shared by all backend plugins
      # See https://backstage.io/docs/tutorials/backend-to-backend-auth for
      # information on the format
      # auth:
      #   keys:
      #     - secret: ${BACKEND_SECRET}
      baseUrl: https://otc.c-one-infra.de:443
      listen:
        port: 7007
        # Uncomment the following host directive to bind to specific interfaces
        # host: 127.0.0.1
      csp:
        connect-src: ["'self'", 'http:', 'https:']
        # Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
        # Default Helmet Content-Security-Policy values can be removed by setting the key to false
      cors:
        origin: https://otc.c-one-infra.de:443
        methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
        credentials: true
      database:
        client: pg
        connection:
          host: ${POSTGRES_HOST}
          port: ${POSTGRES_PORT}
          user: ${POSTGRES_USER}
          password: ${POSTGRES_PASSWORD}
      cache:
        store: memory
      # workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir

    integrations:
      gitea:
        - baseUrl: https://gitea.otc.c-one-infra.de:443
          host: gitea.otc.c-one-infra.de:443
          username: ${GITEA_USERNAME}
          password: ${GITEA_PASSWORD}
        - baseUrl: https://gitea.otc.c-one-infra.de
          host: gitea.otc.c-one-infra.de
          username: ${GITEA_USERNAME}
          password: ${GITEA_PASSWORD}
        - baseUrl: https://forgejo.edf-bootstrap.cx.fg1.ffm.osc.live
          host: forgejo.edf-bootstrap.cx.fg1.ffm.osc.live
    #  github:
    #    - host: github.com
    #      apps:
    #        - $include: github-integration.yaml
    #    - host: github.com
    #      # This is a Personal Access Token or PAT from GitHub. You can find out how to generate this token, and more information
    #      # about setting up the GitHub integration here: https://backstage.io/docs/getting-started/configuration#setting-up-a-github-integration
    #      token: ${GITHUB_TOKEN}
        ### Example for how to add your GitHub Enterprise instance using the API:
        # - host: ghe.example.net
        #   apiBaseUrl: https://ghe.example.net/api/v3
        #   token: ${GHE_TOKEN}

    # Reference documentation http://backstage.io/docs/features/techdocs/configuration
    # Note: After experimenting with basic setup, use CI/CD to generate docs
    # and an external cloud storage when deploying TechDocs for production use-case.
    # https://backstage.io/docs/features/techdocs/how-to-guides#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach
    techdocs:
      builder: 'local' # Alternatives - 'external'
      generator:
        runIn: 'local'
      publisher:
        type: 'local' # Alternatives - 'googleGcs' or 'awsS3'. Read documentation for using alternatives.

    auth:
      environment: development
      session:
        secret: MW2sV-sIPngEl26vAzatV-6VqfsgAx4bPIz7PuE_2Lk=
      providers:
        keycloak-oidc:
          development:
            metadataUrl: ${KEYCLOAK_NAME_METADATA}
            clientId: backstage
            clientSecret: ${KEYCLOAK_CLIENT_SECRET}
            prompt: auto

    scaffolder:
      # see https://backstage.io/docs/features/software-templates/configuration for software template options
        defaultAuthor:
          name: backstage-scaffolder
          email: noreply
        defaultCommitMessage: "backstage scaffolder"
    catalog:
      import:
        entityFilename: catalog-info.yaml
        pullRequestBranchName: backstage-integration
      rules:
        - allow: [Component, System, API, Resource, Location, Template]
      locations:
        # Examples from a public GitHub repository.
        - type: url
          target: https://forgejo.edf-bootstrap.cx.fg1.ffm.osc.live:443/DevFW-CICD/stacks-instances/raw/branch/main/cihe/otc.c-one-infra.de/stacks/ref-implementation/backstage-templates/entities/catalog-info.yaml
          rules:
            - allow: [Component, System, API, Resource, Location, Template, User, Group]
    kubernetes:
      serviceLocatorMethod:
        type: 'multiTenant'
      clusterLocatorMethods:
        - $include: k8s-config.yaml
    argocd:
      username: admin
      password: ${ARGOCD_ADMIN_PASSWORD}
      appLocatorMethods:
        - type: 'config'
          instances:
            - name: in-cluster
              url: https://otc.c-one-infra.de:443/argocd
              username: admin
              password: ${ARGOCD_ADMIN_PASSWORD}
    argoWorkflows:
        baseUrl: ${ARGO_WORKFLOWS_URL}
---
apiVersion: v1
kind: Secret
metadata:
  name: k8s-config
  namespace: backstage
stringData:
  k8s-config.yaml: "type: 'config'\nclusters:\n  - url: https://kubernetes.default.svc.cluster.local\n
    \   name: local\n    authProvider: 'serviceAccount'\n    skipTLSVerify: true\n
    \   skipMetricsLookup: true\n    serviceAccountToken: \n      $file: /var/run/secrets/kubernetes.io/serviceaccount/token\n
    \   caData: \n      $file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n"
---
apiVersion: v1
kind: Service
metadata:
  name: backstage
  namespace: backstage
spec:
  ports:
    - name: http
      port: 7007
      targetPort: http
  selector:
    app: backstage
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: postgresql
  name: postgresql
  namespace: backstage
spec:
  clusterIP: None
  ports:
    - name: postgres
      port: 5432
  selector:
    app: postgresql
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backstage
  namespace: backstage
  annotations:
    argocd.argoproj.io/sync-wave: "20"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backstage
  template:
    metadata:
      labels:
        app: backstage
    spec:
      containers:
        - command:
            - node
            - packages/backend
            - --config
            - config/app-config.yaml
          env:
            - name: LOG_LEVEL
              value: debug
            - name: NODE_TLS_REJECT_UNAUTHORIZED
              value: "0"
            - name: NODE_OPTIONS
              value: "--no-node-snapshot"
          envFrom:
            - secretRef:
                name: backstage-env-vars
            - secretRef:
                name: gitea-credentials
            - secretRef:
                name: argocd-credentials
          image: forgejo.edf-bootstrap.cx.fg1.ffm.osc.live/devfw-cicd/backstage-edp:1.1.0
          imagePullPolicy: Always
          name: backstage
          ports:
            - containerPort: 7007
              name: http
          volumeMounts:
            - mountPath: /app/config
              name: backstage-config
              readOnly: true
      serviceAccountName: backstage
      volumes:
        - name: backstage-config
          projected:
            sources:
              - configMap:
                  items:
                    - key: app-config.yaml
                      path: app-config.yaml
                  name: backstage-config
              - secret:
                  items:
                    - key: k8s-config.yaml
                      path: k8s-config.yaml
                  name: k8s-config
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: postgresql
  name: postgresql
  namespace: backstage
  annotations:
    argocd.argoproj.io/sync-wave: "10"
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgresql
  serviceName: service-postgresql
  template:
    metadata:
      labels:
        app: postgresql
    spec:
      containers:
        - env:
            - name: POSTGRES_DB
              valueFrom:
                secretKeyRef:
                  name: backstage-env-vars
                  key: POSTGRES_DB
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: backstage-env-vars
                  key: POSTGRES_USER
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: backstage-env-vars
                  key: POSTGRES_PASSWORD
          image: docker.io/library/postgres:15.3-alpine3.18
          name: postgres
          ports:
            - containerPort: 5432
              name: postgresdb
          resources:
            limits:
              memory: 500Mi
            requests:
              cpu: 100m
              memory: 300Mi
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
              subPath: postgres
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: "500Mi"
---
apiVersion: generators.external-secrets.io/v1alpha1
kind: Password
metadata:
  name: backstage
  namespace: backstage
spec:
  length: 36
  digits: 5
  symbols: 5
  symbolCharacters: "/-+"
  noUpper: false
  allowRepeat: true
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: backstage-oidc
  namespace: backstage
spec:
  secretStoreRef:
    name: keycloak
    kind: ClusterSecretStore
  refreshInterval: "0"
  target:
    name: backstage-env-vars
    template:
      engineVersion: v2
      data:
        BACKSTAGE_FRONTEND_URL: https://otc.c-one-infra.de:443/backstage
        POSTGRES_HOST: postgresql.backstage.svc.cluster.local
        POSTGRES_PORT: '5432'
        POSTGRES_DB: backstage
        POSTGRES_USER: backstage
        POSTGRES_PASSWORD: "{{.POSTGRES_PASSWORD}}"
        ARGO_WORKFLOWS_URL: https://otc.c-one-infra.de:443/argo-workflows
        KEYCLOAK_NAME_METADATA: https://otc.c-one-infra.de:443/keycloak/realms/cnoe/.well-known/openid-configuration
        KEYCLOAK_CLIENT_SECRET: "{{.BACKSTAGE_CLIENT_SECRET}}"
        ARGOCD_AUTH_TOKEN: "argocd.token={{.ARGOCD_SESSION_TOKEN}}"
        ARGO_CD_URL: 'https://otc.c-one-infra.de/argocd/api/v1/'
  data:
    - secretKey: ARGOCD_SESSION_TOKEN
      remoteRef:
        key: keycloak-clients
        property: ARGOCD_SESSION_TOKEN
    - secretKey: BACKSTAGE_CLIENT_SECRET
      remoteRef:
        key: keycloak-clients
        property: BACKSTAGE_CLIENT_SECRET
  dataFrom:
    - sourceRef:
        generatorRef:
          apiVersion: generators.external-secrets.io/v1alpha1
          kind: Password
          name: backstage
      rewrite:
        - transform:
            template: "POSTGRES_PASSWORD"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: gitea-credentials
  namespace: backstage
spec:
  secretStoreRef:
    name: gitea
    kind: ClusterSecretStore
  refreshInterval: "0"
  target:
    name: gitea-credentials
  data:
    - secretKey: GITEA_USERNAME
      remoteRef:
        key: gitea-credential
        property: username
    - secretKey: GITEA_PASSWORD
      remoteRef:
        key: gitea-credential
        property: password
