diff --git a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-harbor-registry-secret.yaml b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-harbor-registry-secret.yaml index d61db52..f70388d 100644 --- a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-harbor-registry-secret.yaml +++ b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-harbor-registry-secret.yaml @@ -8,7 +8,7 @@ metadata: namespace: avroid-prod annotations: vault.security.banzaicloud.io/vault-addr: "https://vault.avroid.tech" - vault.security.banzaicloud.io/vault-role: "avroid-staging" + vault.security.banzaicloud.io/vault-role: "avroid-prod" vault.security.banzaicloud.io/vault-skip-verify: "false" vault.security.banzaicloud.io/vault-path: "avroid-office" type: kubernetes.io/dockerconfigjson diff --git a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-vault-service-account.yaml b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-vault-service-account.yaml new file mode 100644 index 0000000..09e1db9 --- /dev/null +++ b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/.rbac/argocd-apps-vault-service-account.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/instance: vault-sa + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: vault-operator + app.kubernetes.io/part-of: vault-operator + app.kubernetes.io/managed-by: argocd + name: vault + namespace: avroid-prod diff --git a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/README.md b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/README.md new file mode 100644 index 0000000..976d9c4 --- /dev/null +++ b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/README.md @@ -0,0 +1,68 @@ +# Install [Gitea SonarQube Bot](https://codeberg.org/justusbunsi/gitea-sonarqube-bot/src/branch/main/helm) with [custom container](https://git.avroid.tech/andrey.danin/gitea-sonarqube-bot) + +## Create from version +| Project | Version | +|---------------------|------------| +| Gitea SonarQube Bot | 0.3.4 | +| Custom container | avr-v0.3.4 | + +## Install +Настраиваем для работы файл конфигурации kubectl для подключения к кластеру Kubernetes + +Готовим служебную УЗ для vault (ЭТО АВТОМАТИЗИРОВАНО через ArgoCD): +```bash +kubectl apply -f .rbac/vault-service-account.yaml +kubectl apply -f .rbac/harbor-registry-secret.yaml +``` + +Получаем из Vault секреты с паролями/токенами/сертификатами и выгружаем в окружение оболочки: +```bash +./gitea_sonarqube_bot_values_secrets_init.sh + +source .creds +``` + +Применяем сетевые политики: +```bash +kubectl -n avroid-prod apply -f gitea-sonarqube-bot-network-policy.yaml +``` + +И производим непосредственную установку: + +```bash +helm repo add gitea-sonarqube-bot https://codeberg.org/justusbunsi/gitea-sonarqube-bot/raw/branch/charts/ +helm repo update + +helm install -n avroid-prod gitea-sonarqube-bot gitea-sonarqube-bot/gitea-sonarqube-bot -f values-override.yaml \ + --set app.configuration.gitea.token.value=$GSB_GITEA_TOKEN_VALUE \ + --set app.configuration.gitea.webhook.secret=$GSB_GITEA_WEBHOOK_SECRET \ + --set app.configuration.sonarqube.token.value=$GSB_SONARQUBE_TOKEN_VALUE \ + --set app.configuration.sonarqube.webhook.secret=$GSB_SONARQUBE_WEBHOOK_SECRET \ + --set app.configuration.bitbucket.webhook.secret=$GSB_BITBUCKET_WEBHOOK_SECRET +``` + + +## Upgrade/Changes +Обновление настроек и чарта делаем так: + +В начале сравниваем содержимое `values-override.yaml` с исходным файлом `values.yaml` +(ссылка на исходную версию зафиксирована в заголовке `values-override.yaml`) через diff (IDE лучше). +Или с новой версией `values.yaml` в Helm-чарте. +Вносим необходимые правки, новые опции или добавляем секреты. + +Получаем из Vault секреты с паролями/токенами/сертификатами и выгружаем в окружение оболочки: +```bash +./gitea_sonarqube_bot_values_secrets_init.sh + +source .creds +``` + +Затем применяем: +```bash +helm upgrade -n avroid-prod gitea-sonarqube-bot gitea-sonarqube-bot/gitea-sonarqube-bot -f values-override.yaml \ + --set app.configuration.gitea.token.value=$GSB_GITEA_TOKEN_VALUE \ + --set app.configuration.gitea.webhook.secret=$GSB_GITEA_WEBHOOK_SECRET \ + --set app.configuration.sonarqube.token.value=$GSB_SONARQUBE_TOKEN_VALUE \ + --set app.configuration.sonarqube.webhook.secret=$GSB_SONARQUBE_WEBHOOK_SECRET \ + --set app.configuration.bitbucket.webhook.secret=$GSB_BITBUCKET_WEBHOOK_SECRET +``` diff --git a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/gitea-sonarqube-bot-network-policy.yaml b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/gitea-sonarqube-bot-network-policy.yaml new file mode 100644 index 0000000..bb408d6 --- /dev/null +++ b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/gitea-sonarqube-bot-network-policy.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: gitea-sonarqube-bot-in + namespace: avroid-prod + labels: + app.kubernetes.io/managed-by: manually +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: gitea-sonarqube-bot + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: ingress-nginx + - ports: + - port: 3000 + protocol: TCP +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: gitea-sonarqube-bot-out + namespace: avroid-prod + labels: + app.kubernetes.io/managed-by: manually +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: gitea-sonarqube-bot + policyTypes: + - Egress + ingress: [] + egress: + - to: + - ipBlock: + # office-balancer.avroid.tech + cidr: 10.2.16.2/32 + ports: + - port: 443 + protocol: TCP diff --git a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/gitea_sonarqube_bot_values_secrets_init.sh b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/gitea_sonarqube_bot_values_secrets_init.sh new file mode 100755 index 0000000..8ac693b --- /dev/null +++ b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/gitea_sonarqube_bot_values_secrets_init.sh @@ -0,0 +1,24 @@ +#!/bin/sh +set -e + +rm -rf .creds + +gitea_sonarqube_bot_config_gitea_token_value=$(vault kv get team-devops/accounts/bots/sonarqube/avroid.tech/gitea-sonarqube-bot | grep app.configuration.gitea.token.value | awk '{print $2}') +gitea_sonarqube_bot_config_gitea_webhook_secret=$(vault kv get team-devops/accounts/bots/sonarqube/avroid.tech/gitea-sonarqube-bot | grep app.configuration.gitea.webhook.secret | awk '{print $2}') + +gitea_sonarqube_bot_config_sonarqube_token_value=$(vault kv get team-devops/accounts/bots/sonarqube/avroid.tech/gitea-sonarqube-bot | grep app.configuration.sonarqube.token.value | awk '{print $2}') +gitea_sonarqube_bot_config_sonarqube_webhook_secret=$(vault kv get team-devops/accounts/bots/sonarqube/avroid.tech/gitea-sonarqube-bot | grep app.configuration.sonarqube.webhook.secret | awk '{print $2}') + +gitea_sonarqube_bot_config_bitbucket_webhook_secret=$(vault kv get team-devops/accounts/bots/sonarqube/avroid.tech/gitea-sonarqube-bot | grep app.configuration.bitbucket.webhook.secret | awk '{print $2}') + +cat > .creds << EOF +export GSB_GITEA_TOKEN_VALUE='${gitea_sonarqube_bot_config_gitea_token_value}' +export GSB_GITEA_WEBHOOK_SECRET='${gitea_sonarqube_bot_config_gitea_webhook_secret}' +export GSB_SONARQUBE_TOKEN_VALUE='${gitea_sonarqube_bot_config_sonarqube_token_value}' +export GSB_SONARQUBE_WEBHOOK_SECRET='${gitea_sonarqube_bot_config_sonarqube_webhook_secret}' +export GSB_BITBUCKET_WEBHOOK_SECRET='${gitea_sonarqube_bot_config_bitbucket_webhook_secret}' +EOF + +echo "Run:" +echo ' 1. source .creds' +echo ' 2. kubectl -n avroid-prod apply -f gitea-sonarqube-bot-network-policy.yaml' diff --git a/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/values-override.yaml b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/values-override.yaml new file mode 100644 index 0000000..8d2ee29 --- /dev/null +++ b/clusters/k8s-avroid-office.prod.local/namespaces/avroid-prod/security/gitea-sonarqube-bot/values-override.yaml @@ -0,0 +1,150 @@ +## @section Common parameters + +## @param replicaCount Number of replicas for the bot +replicaCount: 2 + +## ref: https://hub.docker.com/r/justusbunsi/gitea-sonarqube-bot/tags/ +## @param image.repository Image repository +## @param image.pullPolicy Image pull policy +## @param image.tag Image tag (Overrides the image tag whose default is the chart `appVersion`) +image: + repository: harbor.avroid.tech/devops/gitea-sonarqube-bot + tag: "avr-v0.3.4" + +## @param imagePullSecrets Specify docker-registry secret names as an array +imagePullSecrets: + - name: harbor-registry-secret + +## We usually recommend not to specify default resources and to leave this as a conscious +## choice for the user. This also increases chances charts run on environments with little +## resources, such as Minikube. If you do want to specify resources, uncomment the following +## lines, adjust them as necessary, and remove the curly braces after 'resources:'. +## @param resources.limits The resources limits for the container +## @param resources.requests The requested resources for the container +resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi + +## @param nodeSelector Node labels for pod assignment. Evaluated as a template. +## ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: + node-role.kubernetes.io/worker: "" + +## @param podAnnotations Pod annotations. +podAnnotations: + vault.security.banzaicloud.io/vault-addr: "https://vault.avroid.tech" + vault.security.banzaicloud.io/vault-role: "avroid-prod" + vault.security.banzaicloud.io/vault-skip-verify: "false" + vault.security.banzaicloud.io/vault-path: "avroid-office" + +## @section App parameters + +app: + ## @param app.configLocationOverride Override the default location of the configuration file (`/home/bot/config/config.yaml`). **Available since Chart version `0.2.0`. Requires at least image tag `v0.2.0`**. (See values file for details) + ## Setting this will also change the mount point for `.Values.app.configuration` to the directory part of the override value. + configLocationOverride: "" + + ## This object represents the [config.yaml](https://codeberg.org/justusbunsi/gitea-sonarqube-bot/src/branch/main/config/config.example.yaml) provided to the application. + configuration: + ## Gitea related configuration. Necessary for adding/updating comments on repository pull requests + gitea: + ## @param app.configuration.gitea.url Endpoint of your Gitea instance. Must be expandable by '/api/v1' to form the API base path as shown in Swagger UI. + url: "https://git.avroid.tech" + + ## Created access token for the user that shall be used as bot account. + ## User needs "Read project" permissions with access to "Pull Requests" + ## @param app.configuration.gitea.token.value Gitea token as plain text. Can be replaced with `file` key containing path to file. + token: + value: "" + + ## If the sent webhook has a signature header, the bot validates the request payload. If the value does not match, the + ## request will be ignored. + ## The bot looks for `X-Gitea-Signature` header containing the sha256 hmac hash of the plain text secret. If the header + ## exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be validated. + ## @param app.configuration.gitea.webhook.secret Secret for signature header (in plaintext) + ## @extra app.configuration.gitea.webhook.secretFile Path to file containing the plain text secret. Alternative to inline `app.configuration.gitea.webhook.secret` + webhook: + secret: "" + + ## SonarQube related configuration. Necessary for requesting data from the API and processing the webhook. + sonarqube: + ## @param app.configuration.sonarqube.url Endpoint of your SonarQube instance. Must be expandable by '/api' to form the API base path. + url: "https://sonarqube.avroid.tech" + + ## Created access token for the user that shall be used as bot account. + ## User needs "Browse on project" permissions + ## @param app.configuration.sonarqube.token.value SonarQube token as plain text. Can be replaced with `file` key containing path to file. + token: + value: "" + + ## If the sent webhook has a signature header, the bot validates the request payload. If the value does not match, the + ## request will be ignored. + ## The bot looks for `X-Sonar-Webhook-HMAC-SHA256` header containing the sha256 hmac hash of the plain text secret. + ## If the header exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be + ## validated. + ## @param app.configuration.sonarqube.webhook.secret Secret for signature header (in plaintext) + ## @extra app.configuration.sonarqube.webhook.secretFile Path to file containing the plain text secret. Alternative to inline `app.configuration.sonarqube.webhook.secret` + webhook: + secret: "" + + ## List of project mappings to take care of. Webhooks for other projects will be ignored. + ## At least one must be configured. Otherwise, all webhooks (no matter which source) because the bot cannot map on its own. + ## @param app.configuration.projects[0].sonarqube.key Project key inside SonarQube + ## @param app.configuration.projects[0].gitea.owner Repository owner inside Gitea + ## @param app.configuration.projects[0].gitea.name Repository name inside Gitea + projects: + - sonarqube: + key: example:example_sast + ## A repository specification contains the owner name and the repository name itself. The owner can be the name of a + ## real account or an organization in which the repository is located. + gitea: + owner: DevSec + name: sast-demo + + ## Define pull request names from SonarScanner analysis. Default pattern matches the Jenkins Gitea plugin schema. + ## @param app.configuration.namingPattern.regex Regular expression that MUST HAVE exactly ONE GROUP that matches the integer part of the PR. That integer part is identical to the pull request ID in Gitea. + ## @param app.configuration.namingPattern.template Valid Go format string. It MUST have one integer placeholder which will be replaced by the pull request ID. See: https://pkg.go.dev/fmt#hdr-Printing + namingPattern: + regex: ^PR-(\d+)$ + urlregex: ^http.*&pullRequest=PR-(\d+).*$ + template: PR-%d + + bitbucket: + webhook: + secret: "" + +## @section Security parameters + +serviceAccount: + ## @param serviceAccount.create Specifies whether a service account should be created + create: false + ## @param serviceAccount.name The name of the service account to use. If not set and create is true, a name is generated using the fullname template + name: "vault" + +## ref: https://kubernetes.io/docs/user-guide/ingress/ +ingress: + + ## @param ingress.enabled Enable ingress controller resource + enabled: true + + ## @param ingress.className IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) + ## This is supported in Kubernetes 1.18+ and required if you have more than one IngressClass marked as the default for your cluster. + ## ref: https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/ + className: "nginx" + + ## @param ingress.annotations Additional annotations for the Ingress resource. + annotations: + kubernetes.io/ingress.class: nginx + + ## @param ingress.hosts[0].host Host for the ingress resource + ## @param ingress.hosts[0].paths[0].path The path to the bot endpoint + ## @param ingress.hosts[0].paths[0].pathType Ingress path type + hosts: + - host: gitea-sonarqube-bot.avroid.tech + paths: + - path: / + pathType: ImplementationSpecific