diff --git a/cluster-config/.github/workflows/validate-manifests.yaml b/cluster-config/.github/workflows/validate-manifests.yaml new file mode 100644 index 0000000..e1423aa --- /dev/null +++ b/cluster-config/.github/workflows/validate-manifests.yaml @@ -0,0 +1,31 @@ +name: Validate Manifests +on: + push: + branches: + - "*" + pull_request: + branches: + - "*" + +jobs: + lint-yaml: + runs-on: ubuntu-latest + steps: + - name: Code Checkout + uses: actions/checkout@v3 + - name: Validate YAML + uses: ibiqlik/action-yamllint@v3 + with: + format: github + lint-kustomize: + runs-on: ubuntu-latest + steps: + - name: Code Checkout + uses: actions/checkout@v3 + - name: Verify Kustomize CLI Installation + run: | + which kustomize + kustomize version + - name: Validate Manifests + run: | + ./scripts/validate_manifests.sh diff --git a/cluster-config/.gitignore b/cluster-config/.gitignore new file mode 100644 index 0000000..fad2efc --- /dev/null +++ b/cluster-config/.gitignore @@ -0,0 +1,8 @@ +sealed-secrets-secret.yaml +cloud-dns-credentials.yaml +alertmanager.yaml +google-secret.yaml +*-private.yaml +*-private.yml +charts +qnap-tls diff --git a/cluster-config/.yamllint b/cluster-config/.yamllint new file mode 100644 index 0000000..361c2d3 --- /dev/null +++ b/cluster-config/.yamllint @@ -0,0 +1,9 @@ +extends: default + +rules: + document-start: disable + indentation: + indent-sequences: whatever + line-length: disable + truthy: + ignore: .github/workflows/ diff --git a/cluster-config/README.md b/cluster-config/README.md new file mode 100644 index 0000000..705a22e --- /dev/null +++ b/cluster-config/README.md @@ -0,0 +1,136 @@ +# GitOps Cluster Configuration + +This repo contains the cluster configuration I use for my personal OpenShift clusters. Like my other GitOps repos it leverages ArgoCD heavily. This repo originally followed the folder structure defined in the [Standards](https://github.com/gnunn-gitops/standards) repository but there has been some tweaks that need to be reflected back in that document. + +# Structure + +Similar to my standards document, the repo consists of four high level folders: + +* _bootstrap_ - the minimal yaml needed to bootstrap the cluster-config into argocd. It deploys a known sealed-secret private key along with an "app of app" `cluster-config-manager` that deploys the entirety of the cluster configuration. +* _components_ - a base set of kustomize manifests and yaml for applications, operators, configuration and ArgoCD app/project definitions. Everything is inherited from here +* _clusters_ - Cluster specific configuration, this inherits and kustomizes from the components folder and uses an identical structure. +* _tenants_ - Tenant specific artifacts required by different teams using the cluster. For example, a team will likely need a set of namespaces with quotas, there own gitops-operator installation, etc in order to deploy their work. + +While this structure follows the basic principles in my standards document I am in the process of re-factoring the naming as well as attempting to simplify the level of nesting. + +![alt text](https://raw.githubusercontent.com/gnunn-gitops/cluster-config/main/docs/img/argocd.png) + +Finally note that I deliberately have everything in the same repository for demo purposes. Folks dealing with a lot of clusters and tenants will likely want to split things out into multiple repositories. + +## App-Of-App Helm Chart and Layers + +This repository is based on kustomize, and as a result the _bootstrap_ folder consists of a _base_ and _overlays_. The _base_ is the configuration that is required on all clusters whereas the _overlays_ consist of groupings of +clusters as well as specific clusters. + +A helm chart managed by kustomize is used to generate the list of Argo CD Applications using the [App of App](https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/#app-of-apps-pattern) pattern as well as a cluster-config AppProject. I had originally used kustomize to manage the Argo CD Applications directly but this generated a lot of yaml and made overriding applications for specific clusters much more verbose then necessary. This is an example of where templating is a more optimum solution then patching. + +In the bootstrap _base_ and cluster _overlays_ (`bootstrap/overlays/`) there is a `kustomization.yaml` file along with a `values.yaml` file where we use kustomize to generate the Application manifests from a `helm template`. + +This helm chart is run independently at each layer and is aggregated by higher levels. So for example my `local.home` cluster, which is one of my bare-metal servers in my homelab, has an application tree that aggregatesm Applications as follows: + +`base` > `local` > `local.home` + +At each layer the helm chart is run for that layer and generates the Application manifests for that specific layer. The nice thing with this approach is group or cluster specific changes is easy, kustomize can be used to override a lower level layer's Application(s) and point it to a cluster specific version simply by patching it's path and/or repo. + +The `clusters/overlays//components` consists of components that are specific to this cluster or is cluster-specific overriden version of manifests from the _components_ folder. So at the bootstrap level, if the _base_ has an application pointing to manfiests in _components_, this can be overriden in the cluster specific bootstrap by patching it to point to a version in `clusters/overlays//components//`. + +I've opted to use a dot notation to separate groups, i.e `local`, from specific clusters, `local.home` however in the future it may be worth considering seperating this into distinct `groups` and `clusters` folders. + +## Why not ApplicationSet instead of App-of-App Helm Chart? + +Some folks may be wondering why I do not use an ApplicationSet instead of this App-of-App Helm chart. The primary reason is that the Helm chart allows for easily post-processing the generated Applications to enable cluster overrides. While having an ApplicationSet with a list generator delivered by kustomize could also accomplish this, the list generator is simply a list which is challenging to patch correctly with JSON semantics (i.e. you can only reference items by ordinal rather then name. As a result trying to manage patching this would be error-prone if ordering ever changes in the list. + +Other generator types don't allow any post-processing meaning overriding for specific clusters needs to be packaged into the ApplicationSet which I felt was overly cumbersome. + +Having said, the new ApplicationSet feature supporting creating custom generator plugins may make it more amenable for this use case but I have not explored this as of yet. + +## Argo CD Plugin + +From a GitOps purist point of view there is a desire to have everything in git regardless of how many manifests need to be maintained. Thus with +kustomize this can make for a significant number of overlays to account for cluster differences in endpoints (each cluster has its own DNS domain) and other +internal cluster details like cluster name, cluster id, infrastructure id, etc. + +I'm more a pragmatist then a purist, as a result I use a Argo CD Configuration Management Plugin (CMP) to template some per cluster static items as environment +variables to minimize the amount of individual cluster overlays. + +I am using ACM's ability to template in policies to automatically populate the required environment variables, you can see that [here](https://github.com/gnunn-gitops/acm-hub-bootstrap/blob/main/components/policies/gitops/base/manifests/gitops-instance/base/argocd.yaml#L54). + +Note this works because I am using the distributed topology so the Argo CD sitting on each cluster can have unique environment variables. In a centralized topology you could look at adding labels/annotations to cluster secrets and then use the ApplicationSet cluster generator to pass these into Applications as possibly one way to accomplish the same. + +# Usage + +As detailed in the layers section, cluster specific configuration is stored in the bootstrap/overlays folder. To deploy a specific cluster configuration, simply create an application in Argo CD that points to the appropriate cluster folder, i.e. `bootstrap/overlays/{clustername}`. + +Note that in order for kustomize to be able to generate manifests from a helm chart you do need to have Argo CD pass the `--enable-helm` flag to kustomize. You can do this via setting the `kustomizeBuildOptions` in the ArgoCD CR: + +``` +apiVersion: argoproj.io/v1alpha1 +kind: ArgoCD +metadata: + name: openshift-gitops + namespace: openshift-gitops +spec: + kustomizeBuildOptions: "--enable-helm" + ... +``` + +How this bootstrap application gets generated and managed can happen in a variety of different ways: + +* [Red Hat Advanced Cluster Manager](https://www.redhat.com/en/technologies/management/advanced-cluster-management) can use a policy to deploy OpenShift GitOps plus a cluster specific bootstrap application across a fleet of clusters. This is my preferred approach and the [acm-bootstrap-hub](https://github.com/gnunn-gitops/acm-hub-bootstrap) is the repo where I have this policy along with other things I use to bootstrap the ACM Hub cluster. +* Ansible. If you use Ansible for cluster provisioning you can have it deploy the OpenShift GitOps operator plus the bootstrap application +* Other. If you use other automation tools to provision clusters they could do the same as Ansible. + +# Secret Management + +I am currently using the [External Secrets Operator](https://external-secrets.io/latest/) to manage secrets, I am using ACM to automatically bootstrap the token secret needed by ESO to interact with my secrets provider [Doppler](doppler.com) from the Hub cluster. I wrote a blog on this setup [here](https://cloud.redhat.com/blog/external-secrets-operator-and-doppler-with-openshift-gitops). + +I have used Sealed Secrets in the past but as I have expanded my homelab into multiple clusters, plus the occasional ephemeral cloud cluster, I found external secrets easier to manage. + +# Managing Promotion + +A common requirement is for a cluster configuration to be promoted across one or more clusters, i.e a change starts in the lab cluster, gets promoted to non-production and then finally production. + +I am currently trying this and so far commit pinning works well in this scenario, i.e. the lab cluster is pinned to HEAD and always gets the latest and greatest. The other clusters are pinned to specific commits, when you want to promote you simply move the pin forward to the desired commit. + +In cases where a configuration spans multiple repositories you may need to have different commit pins based on the repo. This could be accomplished by labelling the Application objects with the repo and then using a kustomize patch targetted by label. Some improvements to the helm chart would be needed so that labels can be merged between default and specific applications to make this easier to manage. + +Commit pinning for specific applications is also straightforward, either by overriding the default `targetRevision` in the App-of-App Helm chart for a specific application or patching it via kustomize. + +See the repo [cluster-config-pins](https://github.com/gnunn-gitops/cluster-config-pins) for more information on how commit pinning is being used here. + +# Sequence + +This repo uses Argo CD sync waves to configure the configuration in an ordered manner. The following waves are used: + +1. External Secrets Operator +2. Storage (if needed) +3. cert-manager +11. Cluster Configuration (Authentication, AlertManager, etc) +21. Operators (Pipelines, CSO, Compliance, Namespace Operator, etc) +31. Common Apps (Developer Tools) +41. OpenShift Console plugins +51. Tenants + +# Topology + +A note on Argo CD topology preferences. I am a fan of distributed Argo CD for cluster configuration, my preference is to use the default `openshift-gitops` instance for cluster configuration and have an ACM Policy deploy OpenShift GitOps on each cluster. My preference for distributed Argo CD versus centralized Argo CD is to remove the Single-Point-Of-Failure (SPOF) as well mitigate any scalability issues when dealing with hundreds of clusters. + +I am also a big fan of separating the cluster configuration use case from application deployment (i.e the stuff Application teams push out) into separate Argo CD instances for the following reasons: + +* Argo CD uses a single serviceaccount for the application-controller which must have enough k8s permissions to pusn out the manifests. By it's nature the cluster configuration use case requires near cluster-admin level permissions at the SA level and while you can remove access to this for App teams using Argo RBAC I prefer a more isolated approach. +* As mentioned I prefer a distributed Argo CD topology for cluster configuration, however a more centralized model with respect to Argo CD instance(s)for application teams provides them with a single pane of glass. This can be very useful to them when a team's applications are distributed across multiple clusters. For cluster-configuration we can achieve the single pane of glass with ACM which is ideal for Ops teams. + +# Tenant Configuration + +Tenants are managed via a helm chart and an ApplicationSet with the git generator, it basically follows the high level approach laid out in this [blog](https://cloud.redhat.com/blog/project-onboarding-using-gitops-and-helm) from Thomas Jungbauer. + +I am using my own Helm chart and this chart is wrapped in kustomize and leverages the helm inflator feature in kustomize. The benefit of this approach is that using kustomize makes it easy to add additional, tenant specific resources and avoids +the helm chart having to be an all singing all dancing sort of thing. + +As an example, you can set the quota size (small, medium, large) you want in the chart but if you want a custom quota you just create your own quota object versus the helm chart having to support a custom quota. + +Finally note that tenant configuration is exempted from commit pinning, it doesn't make much sense to have promotions for individual tenants and structural promotion is handled already by versioning the helm chart. + +# Other Notes + +I am using annotation tracking with Argo CD and as result am not using IgnoreExtraneous (though I may still have some historical examples in the repo). Annotation tracking provides more capabilities then the default label tracking and should always be used to mitigate false positives from operator created resources. diff --git a/cluster-config/bootstrap.sh b/cluster-config/bootstrap.sh new file mode 100755 index 0000000..412c9fd --- /dev/null +++ b/cluster-config/bootstrap.sh @@ -0,0 +1,10 @@ +if [ $# -lt 1 ]; then + echo "No overlay specified, please specify an overlay from bootstrap/overlays" + exit 1 +else + OVERLAY=$1 + echo "Configuring cluster ${OVERLAY}" +fi + +oc project openshift-gitops +kustomize build bootstrap/overlays/${OVERLAY} --enable-helm | oc apply -f - diff --git a/cluster-config/bootstrap/base/kustomization.yaml b/cluster-config/bootstrap/base/kustomization.yaml new file mode 100644 index 0000000..cb839aa --- /dev/null +++ b/cluster-config/bootstrap/base/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops diff --git a/cluster-config/bootstrap/base/values.yaml b/cluster-config/bootstrap/base/values.yaml new file mode 100644 index 0000000..120eafe --- /dev/null +++ b/cluster-config/bootstrap/base/values.yaml @@ -0,0 +1,108 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: base + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +projects: + + cluster-config: + annotations: + notifications.argoproj.io/subscribe.on-sync-failed.slack: cluster-gitops + notifications.argoproj.io/subscribe.on-health-degraded.slack: cluster-gitops + description: Project for overall cluster configuration + namespace: openshift-gitops + sourceRepos: + - https://github.com/gnunn-gitops/cluster-config + - https://github.com/redhat-cop/gitops-catalog + - https://github.com/gnunn-gitops/acm-hub-bootstrap + destinations: | + - namespace: '*' + server: https://kubernetes.default.svc + extraFields: | + clusterResourceWhitelist: + - group: '*' + kind: '*' + +applications: + + banner: + annotations: + argocd.argoproj.io/sync-wave: '11' + source: + path: components/banner/base + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + compliance-operator: + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: openshift-compliance + source: + path: components/compliance-operator/overlays/cis-compliance + + container-security: + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: openshift-operators + source: + path: components/container-security-operator/overlays/stable-3.13 + + external-secrets: + annotations: + argocd.argoproj.io/sync-wave: '1' + destination: + namespace: openshift-operators + source: + path: components/eso/overlays/aggregate + + helm-repos: + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '11' + source: + path: components/helm-repos/base + + pipeline-operator: + annotations: + argocd.argoproj.io/sync-wave: "21" + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + destination: + namespace: openshift-operators + source: + path: components/pipelines-operator/overlays/chains + syncPolicyRetry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + + dev-console-plugin: + destination: + namespace: dev-console-plugin + argocd.argoproj.io/sync-wave: '41' + source: + path: components/dev-console-plugin/base + + gitops-admin-plugin: + destination: + namespace: gitops-admin-plugin + argocd.argoproj.io/sync-wave: '41' + source: + path: components/gitops-admin-plugin/base diff --git a/cluster-config/bootstrap/components/acm-hub/kustomization.yaml b/cluster-config/bootstrap/components/acm-hub/kustomization.yaml new file mode 100644 index 0000000..5ea1ba8 --- /dev/null +++ b/cluster-config/bootstrap/components/acm-hub/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops diff --git a/cluster-config/bootstrap/components/acm-hub/values.yaml b/cluster-config/bootstrap/components/acm-hub/values.yaml new file mode 100644 index 0000000..f42c48e --- /dev/null +++ b/cluster-config/bootstrap/components/acm-hub/values.yaml @@ -0,0 +1,54 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: local.hub + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +applications: + + acm-hub: + annotations: + argocd.argoproj.io/sync-wave: '21' + labels: + repo: acm-hub-bootstrap + destinations: + namespace: open-cluster-management + source: + repoURL: https://github.com/gnunn-gitops/acm-hub-bootstrap.git + path: components/apps/acm/overlays/hub + + acm-observability: + annotations: + argocd.argoproj.io/sync-wave: '31' + labels: + repo: acm-hub-bootstrap + destinations: + namespace: open-cluster-management-observability + source: + repoURL: https://github.com/gnunn-gitops/acm-hub-bootstrap.git + path: components/apps/acm/overlays/observability + + acm-policies: + enableAutoSync: false + annotations: + argocd.argoproj.io/sync-wave: '31' + labels: + repo: acm-hub-bootstrap + destinations: + namespace: acm-policies + source: + repoURL: https://github.com/gnunn-gitops/acm-hub-bootstrap.git + path: bootstrap/policies/overlays/default + extraSourceFields: | + plugin: + name: setenv-cmp-plugin diff --git a/cluster-config/bootstrap/components/kyverno/kustomization.yaml b/cluster-config/bootstrap/components/kyverno/kustomization.yaml new file mode 100644 index 0000000..5ea1ba8 --- /dev/null +++ b/cluster-config/bootstrap/components/kyverno/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops diff --git a/cluster-config/bootstrap/components/kyverno/values.yaml b/cluster-config/bootstrap/components/kyverno/values.yaml new file mode 100644 index 0000000..21d0fa2 --- /dev/null +++ b/cluster-config/bootstrap/components/kyverno/values.yaml @@ -0,0 +1,43 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: local.hub + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +applications: + + kyverno: + enabled: false + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: kyverno + source: + path: components/kyverno/overlays/policies + syncPolicyRetry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + extraFields: | + ignoreDifferences: + - group: kyverno.io + kind: ClusterPolicy + jsonPointers: + - /spec/rules + - group: kyverno.io + kind: Policy + jsonPointers: + - /spec/rules diff --git a/cluster-config/bootstrap/components/sno/kustomization.yaml b/cluster-config/bootstrap/components/sno/kustomization.yaml new file mode 100644 index 0000000..5ea1ba8 --- /dev/null +++ b/cluster-config/bootstrap/components/sno/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops diff --git a/cluster-config/bootstrap/components/sno/values.yaml b/cluster-config/bootstrap/components/sno/values.yaml new file mode 100644 index 0000000..4ac70ee --- /dev/null +++ b/cluster-config/bootstrap/components/sno/values.yaml @@ -0,0 +1,41 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: local.hub + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +applications: + + registry: + annotations: + argocd.argoproj.io/sync-wave: '5' + destination: + namespace: openshift-image-registry + source: + path: components/registry-sno/base + + defrag-etcd: + annotations: + argocd.argoproj.io/sync-wave: '99' + destination: + namespace: openshift-etcd + source: + path: components/defrag-etcd/base + + cleanup-completed-pods: + annotations: + argocd.argoproj.io/sync-wave: '99' + destination: + namespace: clean-completed-pods + source: + path: components/clean-completed-pods/base diff --git a/cluster-config/bootstrap/overlays/local.aws/kustomization.yaml b/cluster-config/bootstrap/overlays/local.aws/kustomization.yaml new file mode 100644 index 0000000..99d0c82 --- /dev/null +++ b/cluster-config/bootstrap/overlays/local.aws/kustomization.yaml @@ -0,0 +1,25 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: argocd-app-of-app + version: 0.2.4 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops + releaseName: argocd-app-of-app-0.2.4 + +resources: +- ../local + +patches: + - target: + kind: Application + name: compliance-operator + patch: |- + - op: replace + path: /spec/source/path + value: 'components/apps/compliance-operator/overlays/cis-compliance' + - op: replace + path: /spec/source/repoURL + value: 'https://github.com/gnunn-gitops/cluster-config' diff --git a/cluster-config/bootstrap/overlays/local.aws/values.yaml b/cluster-config/bootstrap/overlays/local.aws/values.yaml new file mode 100644 index 0000000..11bd112 --- /dev/null +++ b/cluster-config/bootstrap/overlays/local.aws/values.yaml @@ -0,0 +1,14 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +applications: diff --git a/cluster-config/bootstrap/overlays/local.home/kustomization.yaml b/cluster-config/bootstrap/overlays/local.home/kustomization.yaml new file mode 100644 index 0000000..15bb466 --- /dev/null +++ b/cluster-config/bootstrap/overlays/local.home/kustomization.yaml @@ -0,0 +1,24 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops + +components: +- ../../components/sno + +resources: +- ../local + +patches: + - target: + kind: Application + name: compliance-operator + patch: |- + - op: replace + path: /spec/source/path + value: 'components/compliance-operator/overlays/cis-compliance-master-only' diff --git a/cluster-config/bootstrap/overlays/local.home/values.yaml b/cluster-config/bootstrap/overlays/local.home/values.yaml new file mode 100644 index 0000000..60aede4 --- /dev/null +++ b/cluster-config/bootstrap/overlays/local.home/values.yaml @@ -0,0 +1,122 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: local.home + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +projects: + + demo: + description: Project for ad-hoc demos and testing + sourceRepos: + - "*" + destinations: | + - namespace: '*' + server: https://kubernetes.default.svc + extraFields: | + clusterResourceWhitelist: + - group: '*' + kind: '*' + +applications: + + lvm-operator: + annotations: + argocd.argoproj.io/sync-wave: '2' + destination: + namespace: openshift-storage + source: + path: clusters/overlays/local.home/components/lvm-operator + + acs-secured-cluster: + annotations: + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: rhacs-operator + source: + path: components/acs-operator/overlays/secured-cluster + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + console-links: + annotations: + argocd.argoproj.io/sync-wave: '11' + source: + path: clusters/overlays/local.home/components/consolelinks + + cost-management: + annotations: + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: costmanagement-metrics-operator + source: + path: clusters/overlays/local.home/components/cost-management-operator + + lokistack: + enabled: false + annotations: + argocd.argoproj.io/sync-wave: '21' + source: + path: clusters/overlays/local.home/components/lokistack + syncPolicyRetry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + + node-config: + annotations: + argocd.argoproj.io/sync-wave: '99' + source: + path: clusters/overlays/local.home/components/node-config + + rollout-manager: + annotations: + argocd.argoproj.io/sync-wave: '31' + source: + path: components/rollout-manager/base + +# Tenants + gitops: + project: cluster-config + annotations: + argocd.argoproj.io/sync-wave: '50' + destination: + namespace: gitops + source: + path: components/gitops-operator/overlays/shared + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + tenant-secrets: + project: cluster-config + labels: + repo: use-head + annotations: + argocd.argoproj.io/sync-wave: '50' + destination: + namespace: tenant-secrets + source: + path: components/tenant-secrets/base + + tenants: + project: cluster-config + labels: + repo: use-head + annotations: + argocd.argoproj.io/sync-wave: '51' + source: + path: clusters/overlays/local.home/components/tenants diff --git a/cluster-config/bootstrap/overlays/local.hub/kustomization.yaml b/cluster-config/bootstrap/overlays/local.hub/kustomization.yaml new file mode 100644 index 0000000..ecd0354 --- /dev/null +++ b/cluster-config/bootstrap/overlays/local.hub/kustomization.yaml @@ -0,0 +1,32 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops + +components: +- ../../components/acm-hub +- ../../components/sno + +resources: +- ../local + +patches: + - target: + kind: Application + name: compliance-operator + patch: |- + - op: replace + path: /spec/source/path + value: 'components/compliance-operator/overlays/cis-compliance-master-only' + - target: + kind: Application + name: external-secrets + patch: |- + - op: replace + path: /spec/source/path + value: 'clusters/overlays/local.hub/components/eso' diff --git a/cluster-config/bootstrap/overlays/local.hub/values.yaml b/cluster-config/bootstrap/overlays/local.hub/values.yaml new file mode 100644 index 0000000..e74ca0c --- /dev/null +++ b/cluster-config/bootstrap/overlays/local.hub/values.yaml @@ -0,0 +1,160 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: local.hub + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +applications: + + node-config: + annotations: + argocd.argoproj.io/sync-wave: '0' + source: + path: clusters/overlays/local.hub/components/node-config + + odf-operator: + annotations: + argocd.argoproj.io/sync-wave: '1' + source: + path: components/odf-operator/operator/overlays/no-registry + + lvm-operator: + annotations: + argocd.argoproj.io/sync-wave: '2' + destination: + namespace: openshift-storage + source: + path: clusters/overlays/local.hub/components/lvm-operator + + odf-instance: + annotations: + argocd.argoproj.io/sync-wave: '2' + destination: + namespace: openshift-storage + source: + path: components/odf-operator/instance/base + + acs: + annotations: + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: stackrox + source: + path: clusters/overlays/local.hub/components/acs-operator + + acs-config: + annotations: + argocd.argoproj.io/sync-wave: '31' + destination: + namespace: stackrox + source: + path: components/acs-config/base + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + amq-streams: + enabled: false + annotations: + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: openshift-gitops + source: + path: components/amq-streams/overlays/amq-streams-2.7.x/ + + trusted-profile-analyzer-prereqs: + enabled: false + annotations: + argocd.argoproj.io/sync-wave: '31' + destination: + namespace: openshift-gitops + source: + path: components/trusted-profile-analyzer/prereqs/base + + # acm-clusters: + # annotations: + # argocd.argoproj.io/sync-wave: '31' + # labels: + # repo: acm-hub-bootstrap + # destinations: + # namespace: openshift-gitops + # source: + # repoURL: https://github.com/gnunn-gitops/acm-hub-bootstrap.git + # path: components/clusters/base + + # Disable while we work this out + nmstate: + enabled: true + source: + path: clusters/overlays/local.hub/components/nmstate + + console-links: + annotations: + argocd.argoproj.io/sync-wave: '11' + source: + path: clusters/overlays/local.hub/components/consolelinks + + dev-tools: + annotations: + argocd.argoproj.io/sync-wave: '31' + destination: + namespace: dev-tools + source: + path: components/dev-tools/overlays/default + + quay-registry: + # leave disabled unless needed for demo + enabled: false + annotations: + argocd.argoproj.io/sync-wave: '21' + source: + path: clusters/overlays/local.hub/components/quay-registry-operator + + cost-management: + annotations: + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: costmanagement-metrics-operator + source: + path: clusters/overlays/local.hub/components/cost-management-operator + + lokistack: + enabled: false + annotations: + argocd.argoproj.io/sync-wave: '21' + source: + path: clusters/overlays/local.hub/components/lokistack + syncPolicyRetry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + + kyverno-acm: + enabled: false + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: acm-policies + source: + path: components/kyverno-acm/base + + rhtas-operator: + annotations: + argocd.argoproj.io/sync-wave: '21' + destination: + namespace: trusted-artifact-signer + source: + path: clusters/overlays/local.hub/components/rhtas-operator diff --git a/cluster-config/bootstrap/overlays/local/README.md b/cluster-config/bootstrap/overlays/local/README.md new file mode 100644 index 0000000..8e819e5 --- /dev/null +++ b/cluster-config/bootstrap/overlays/local/README.md @@ -0,0 +1,3 @@ +Applications to support my local home lab environment. This isn't limited to my +on-prem environment but can also include cloud clusters. This overlay +includes items for consistency in my homelab setup such as RBAC, authentication (Keycloak), etc. diff --git a/cluster-config/bootstrap/overlays/local/kustomization.yaml b/cluster-config/bootstrap/overlays/local/kustomization.yaml new file mode 100644 index 0000000..1ec866c --- /dev/null +++ b/cluster-config/bootstrap/overlays/local/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops + +resources: +- ../../base diff --git a/cluster-config/bootstrap/overlays/local/values.yaml b/cluster-config/bootstrap/overlays/local/values.yaml new file mode 100644 index 0000000..65da0ed --- /dev/null +++ b/cluster-config/bootstrap/overlays/local/values.yaml @@ -0,0 +1,83 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + labels: + app-source: local.hub + repo: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + +applications: + + authentication: + annotations: + argocd.argoproj.io/sync-wave: '4' + destination: + namespace: openshift-config + source: + path: components/oauth/overlays/homelab + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + cert-manager-operator: + annotations: + argocd.argoproj.io/sync-wave: "2" + destination: + namespace: cert-manager-operator + source: + path: components/cert-manager-operator/aggregate/overlays/letsencrypt + + certificates: + annotations: + argocd.argoproj.io/sync-wave: "3" + destination: + namespace: cert-manager-operator + source: + path: components/certificates/base + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + alertmanager: + annotations: + argocd.argoproj.io/sync-wave: '11' + destination: + namespace: openshift-monitoring + source: + path: components/alertmanager/base + + openshift-monitoring: + annotations: + argocd.argoproj.io/sync-wave: '11' + destination: + namespace: openshift-monitoring + source: + path: components/openshift-monitoring/base + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + # syncOptions: + # - RespectIgnoreDifferences=true + # extraFields: | + # ignoreDifferences: + # - group: "" + # kind: ConfigMap + # jsonPointers: + # - /data/config.yaml/prometheusK8s/externalLabels/managed-cluster + # name: cluster-monitoring-config + # namespace: openshift-monitoring + + rbac: + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '11' + source: + path: components/rbac/base diff --git a/cluster-config/bootstrap/overlays/rhdp/kustomization.yaml b/cluster-config/bootstrap/overlays/rhdp/kustomization.yaml new file mode 100644 index 0000000..50867e7 --- /dev/null +++ b/cluster-config/bootstrap/overlays/rhdp/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: argocd-app-of-app + version: 0.4.1 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: openshift-gitops + +resources: +- ../../base + +patches: + - target: + kind: Application + name: compliance-operator + patch: |- + - op: replace + path: /spec/source/path + value: 'components/compliance-operator/overlays/cis-compliance-master-only' diff --git a/cluster-config/bootstrap/overlays/rhdp/values.yaml b/cluster-config/bootstrap/overlays/rhdp/values.yaml new file mode 100644 index 0000000..135c249 --- /dev/null +++ b/cluster-config/bootstrap/overlays/rhdp/values.yaml @@ -0,0 +1,92 @@ +default: + app: + enabled: true + enableAutoSync: true + autoSyncPrune: false + project: cluster-config + destination: + namespace: openshift-gitops + server: https://kubernetes.default.svc + source: + repoURL: https://github.com/gnunn-gitops/cluster-config.git + targetRevision: HEAD + labels: + app-source: rhdp + +applications: + + # acs: + # annotations: + # argocd.argoproj.io/compare-options: IgnoreExtraneous + # argocd.argoproj.io/sync-wave: '21' + # source: + # path: components/acs-operator/overlays/oauth + + # acs-tokens: + # annotations: + # argocd.argoproj.io/compare-options: IgnoreExtraneous + # argocd.argoproj.io/sync-wave: '61' + # source: + # path: tenants/acs-tokens/base + + authentication: + annotations: + argocd.argoproj.io/sync-wave: '4' + destination: + namespace: openshift-config + source: + path: components/oauth/overlays/homelab + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + rbac: + annotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + argocd.argoproj.io/sync-wave: '11' + source: + path: components/rbac/base + + openshift-monitoring: + annotations: + argocd.argoproj.io/sync-wave: '11' + destination: + namespace: openshift-monitoring + source: + path: components/openshift-monitoring/base + extraSourceFields: | + plugin: + name: setenv-cmp-plugin + + # product-catalog-root: + # project: cluster-config + # annotations: + # argocd.argoproj.io/compare-options: IgnoreExtraneous + # argocd.argoproj.io/sync-wave: '51' + # source: + # path: tenants/product-catalog/argocd/root/base + + # kyverno: + # annotations: + # argocd.argoproj.io/compare-options: IgnoreExtraneous + # argocd.argoproj.io/sync-wave: '21' + # destination: + # namespace: kyverno + # source: + # path: components/kyverno/overlays/policies + # syncPolicyRetry: + # limit: 5 + # backoff: + # duration: 5s + # factor: 2 + # maxDuration: 3m + # extraFields: | + # ignoreDifferences: + # - group: kyverno.io + # kind: ClusterPolicy + # jsonPointers: + # - /spec/rules + # - group: kyverno.io + # kind: Policy + # jsonPointers: + # - /spec/rules diff --git a/cluster-config/clusters/README.md b/cluster-config/clusters/README.md new file mode 100644 index 0000000..faff253 --- /dev/null +++ b/cluster-config/clusters/README.md @@ -0,0 +1 @@ +Cluster specific overlays go here, typically each cluster will have a list of ArgoCD apps required for the configuration managed by the "app of app" pattern expressed in a corresponding overlay in the `/bootstrap/overlays` directory. diff --git a/cluster-config/clusters/overlays/local.aws/README.md b/cluster-config/clusters/overlays/local.aws/README.md new file mode 100644 index 0000000..ba1e461 --- /dev/null +++ b/cluster-config/clusters/overlays/local.aws/README.md @@ -0,0 +1,3 @@ +#### Home (local) Cluster + +This is a cluster deployed in AWS using cluster.ocplab-aws.com for base DNS. diff --git a/cluster-config/clusters/overlays/local.aws/components/cost-management-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.aws/components/cost-management-operator/kustomization.yaml new file mode 100644 index 0000000..af4c493 --- /dev/null +++ b/cluster-config/clusters/overlays/local.aws/components/cost-management-operator/kustomization.yaml @@ -0,0 +1,13 @@ +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 + +resources: + - https://github.com/redhat-cop/gitops-catalog/cost-management-operator/overlays/aggregate + +patchesJson6902: + - path: patch-source-and-name.yaml + target: + group: koku-metrics-cfg.openshift.io + kind: KokuMetricsConfig + name: instance + version: v1beta1 diff --git a/cluster-config/clusters/overlays/local.aws/components/cost-management-operator/patch-source-and-name.yaml b/cluster-config/clusters/overlays/local.aws/components/cost-management-operator/patch-source-and-name.yaml new file mode 100644 index 0000000..9e27f24 --- /dev/null +++ b/cluster-config/clusters/overlays/local.aws/components/cost-management-operator/patch-source-and-name.yaml @@ -0,0 +1,6 @@ +- op: replace + path: /spec/source/name + value: aws.cluster +- op: replace + path: /metadata/name + value: aws-cluster diff --git a/cluster-config/clusters/overlays/local.aws/components/openshift-monitoring/cluster-monitoring-config-cm.yaml b/cluster-config/clusters/overlays/local.aws/components/openshift-monitoring/cluster-monitoring-config-cm.yaml new file mode 100644 index 0000000..917af09 --- /dev/null +++ b/cluster-config/clusters/overlays/local.aws/components/openshift-monitoring/cluster-monitoring-config-cm.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cluster-monitoring-config + namespace: openshift-monitoring +data: + config.yaml: | + enableUserWorkload: true + prometheusK8s: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + storageClassName: gp3-csi + volumeMode: Filesystem + resources: + requests: + storage: 40Gi diff --git a/cluster-config/clusters/overlays/local.aws/components/openshift-monitoring/kustomization.yaml b/cluster-config/clusters/overlays/local.aws/components/openshift-monitoring/kustomization.yaml new file mode 100644 index 0000000..8db0fd3 --- /dev/null +++ b/cluster-config/clusters/overlays/local.aws/components/openshift-monitoring/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- cluster-monitoring-config-cm.yaml diff --git a/cluster-config/clusters/overlays/local.home/README.md b/cluster-config/clusters/overlays/local.home/README.md new file mode 100644 index 0000000..0a1a4f4 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/README.md @@ -0,0 +1,3 @@ +#### Home (local) Cluster + +This is my home cluster which runs on a server under my desk and uses the highly original cluster name of 'home'. It runs in libvirt on a Ryzen 3900x server with 128 GB of memory. It is typically configured as three combined master/worker nodes with 7 vCPU and 35 GB per node. diff --git a/cluster-config/clusters/overlays/local.home/components/clusterversion/base/clusterversion.yaml b/cluster-config/clusters/overlays/local.home/components/clusterversion/base/clusterversion.yaml new file mode 100644 index 0000000..802e718 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/clusterversion/base/clusterversion.yaml @@ -0,0 +1,11 @@ +# apiVersion: config.openshift.io/v1 +# kind: ClusterVersion +# metadata: +# name: version +# spec: +# channel: fast-4.8 +# clusterID: 4d11acb7-286f-42e1-868c-55f1e15687c7 +# desiredUpdate: +# image: quay.io/openshift-release-dev/ocp-release@sha256:bf48faa639523b73131ec7c91637d5c94d33a4afe09ac8bdad672862f5e86ccb +# version: 4.8.14 +# upstream: https://api.openshift.com/api/upgrades_info/v1/graph diff --git a/cluster-config/clusters/overlays/local.home/components/clusterversion/base/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/clusterversion/base/kustomization.yaml new file mode 100644 index 0000000..7e5b852 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/clusterversion/base/kustomization.yaml @@ -0,0 +1,5 @@ +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 + +resources: + - clusterversion.yaml diff --git a/cluster-config/clusters/overlays/local.home/components/consolelinks/acs-consolelink.yaml b/cluster-config/clusters/overlays/local.home/components/consolelinks/acs-consolelink.yaml new file mode 100644 index 0000000..5f4344b --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/consolelinks/acs-consolelink.yaml @@ -0,0 +1,11 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: acs +spec: + href: 'https://central-stackrox.apps.hub.ocplab.com' + location: ApplicationMenu + text: Advanced Cluster Security + applicationMenu: + section: Red Hat Applications + imageURL: https://central-stackrox.apps.hub.ocplab.com/static/media/rh-favicon.0110fdfc5cab55416acf.ico diff --git a/cluster-config/clusters/overlays/local.home/components/consolelinks/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/consolelinks/kustomization.yaml new file mode 100644 index 0000000..e96de1a --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/consolelinks/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../../../../components/consolelinks/base + - acs-consolelink.yaml + - nexus-consolelink.yaml + - sonarqube-consolelink.yaml + - tekton-hub-link.yaml diff --git a/cluster-config/clusters/overlays/local.home/components/consolelinks/nexus-consolelink.yaml b/cluster-config/clusters/overlays/local.home/components/consolelinks/nexus-consolelink.yaml new file mode 100644 index 0000000..0b4598b --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/consolelinks/nexus-consolelink.yaml @@ -0,0 +1,11 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: nexus +spec: + href: 'https://nexus-dev-tools.apps.hub.ocplab.com' + location: ApplicationMenu + text: Nexus + applicationMenu: + section: Tools + imageURL: https://nexus-dev-tools.apps.hub.ocplab.com/favicon.png diff --git a/cluster-config/clusters/overlays/local.home/components/consolelinks/sonarqube-consolelink.yaml b/cluster-config/clusters/overlays/local.home/components/consolelinks/sonarqube-consolelink.yaml new file mode 100644 index 0000000..fc9dfd2 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/consolelinks/sonarqube-consolelink.yaml @@ -0,0 +1,11 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: sonarqube +spec: + href: 'https://sonarqube-dev-tools.apps.hub.ocplab.com' + location: ApplicationMenu + text: SonarQube + applicationMenu: + section: Tools + imageURL: https://sonarqube-dev-tools.apps.hub.ocplab.com/favicon.ico diff --git a/cluster-config/clusters/overlays/local.home/components/consolelinks/tekton-hub-link.yaml b/cluster-config/clusters/overlays/local.home/components/consolelinks/tekton-hub-link.yaml new file mode 100644 index 0000000..568a278 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/consolelinks/tekton-hub-link.yaml @@ -0,0 +1,211 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: tekton-hub +spec: + href: 'https://tekton-hub-ui-openshift-pipelines.apps.hub.ocplab.com' + location: ApplicationMenu + text: Tekton Hub + applicationMenu: + section: Red Hat Applications + imageURL: data:image/png;base64,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 + AElFTkSuQmCC diff --git a/cluster-config/clusters/overlays/local.home/components/cost-management-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/cost-management-operator/kustomization.yaml new file mode 100644 index 0000000..f4ca438 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/cost-management-operator/kustomization.yaml @@ -0,0 +1,15 @@ +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 + +namespace: costmanagement-metrics-operator + +resources: + - https://github.com/redhat-cop/gitops-catalog/cost-management-operator/overlays/aggregate + +patchesJson6902: + - path: patch-source-and-name.yaml + target: + group: costmanagement-metrics-cfg.openshift.io + kind: CostManagementMetricsConfig + name: config + version: v1beta1 diff --git a/cluster-config/clusters/overlays/local.home/components/cost-management-operator/patch-source-and-name.yaml b/cluster-config/clusters/overlays/local.home/components/cost-management-operator/patch-source-and-name.yaml new file mode 100644 index 0000000..424ce63 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/cost-management-operator/patch-source-and-name.yaml @@ -0,0 +1,6 @@ +- op: replace + path: /spec/source/name + value: Home +- op: replace + path: /metadata/name + value: home-cluster diff --git a/cluster-config/clusters/overlays/local.home/components/lokistack/README.md b/cluster-config/clusters/overlays/local.home/components/lokistack/README.md new file mode 100644 index 0000000..4f269bb --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/lokistack/README.md @@ -0,0 +1,54 @@ + + +### Introduction + +Installs the Tech Preview LokiStack for cluster logging using local QNAP NAS for object storage. + +Installation is based on docs here: + +https://github.com/grafana/loki/blob/main/operator/docs/forwarding_logs_to_gateway.md#openshift-logging + +# Accessing logs + +You can access the logs using the logcli tool from grafana: + +https://github.com/grafana/loki/releases/tag/v2.5.0 + +Example queries: + +View raw application logs: +``` +export LOKI_ADDR=http://lokistack-openshift-logging.apps.home.ocplab.com/api/logs/v1/application +logcli --bearer-token="$(oc whoami -t)" query '{kubernetes_namespace_name="product-catalog-dev"}' +``` + +View applicatons logs textually without JSON: +``` +export LOKI_ADDR=http://lokistack-openshift-logging.apps.home.ocplab.com/api/logs/v1/application +logcli --bearer-token="$(oc whoami -t)" query '{kubernetes_namespace_name="product-catalog-dev", kubernetes_container_name="server"}' --output=raw | jq '."@timestamp",.kubernetes.pod_name,.level,.message' | paste - - - - +``` + +View infrastructure logs: +``` +export LOKI_ADDR=http://lokistack-openshift-logging.apps.home.ocplab.com/api/logs/v1/infrastructure +logcli --bearer-token="$(oc whoami -t)" query '{kubernetes_namespace_name="openshift-logging"}' +``` + +### Storage Secret + +You will need a storage secret for your S3 bucket for Loki to use, format of secret is as follows: + +``` +apiVersion: v1 +data: + access_key_id: XXXXXX + access_key_secret: XXXXXX + bucketnames: XXXXXX + endpoint: XXXXXXXXXXXX +kind: Secret +metadata: + name: loki-storage + namespace: openshift-logging +``` + +The sealed secret here is referencing Minio running on my QNAP NAS so non AWS S3 buckets do work fine. diff --git a/cluster-config/clusters/overlays/local.home/components/lokistack/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/lokistack/kustomization.yaml new file mode 100644 index 0000000..2d53747 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/lokistack/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../../../../components/loki/operator/cluster-logging/base + - ../../../../../components/loki/operator/loki/base + - ../../../../../components/loki/instance/overlays/sno + - loki-storage-qnap-secret.yaml diff --git a/cluster-config/clusters/overlays/local.home/components/lokistack/loki-storage-qnap-secret.yaml b/cluster-config/clusters/overlays/local.home/components/lokistack/loki-storage-qnap-secret.yaml new file mode 100644 index 0000000..82f08f0 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/lokistack/loki-storage-qnap-secret.yaml @@ -0,0 +1,16 @@ +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: loki-storage + namespace: openshift-logging +spec: + encryptedData: + access_key_id: AgADsXMtym0OLY598xcLZ4e6zPgh9x3KtCRX59K3J/LriPJPwNuMugAMZcHjLaA9nm+Rwqg095uhGD0pUxK5N336fMiMJ+7WpzMsR8nqMS3eoOtxhXBwML5wXqLmpf2FSxujUXws847JsohHtZiCg6ZBlWuJ2pEaCz6yPecMU8dixz+7OMs079origgakI0FjHlEPMn6BOhAOR4TMCt877mNmeLWrmxNEQt3ql4qMvNH3Ru8G4YijmO+jS9OQYqXYwTbO237zx+D3DDw0PAuUzqMIKXSZZdGNmATXIROu9+4TJGT6YnraMxON81F4t78D+y6reM6AIXN49SDcIxpmSZrtLJ5QQesOPbZ+x4mdR2Rj4RaqyktuNaBknn+CUCtx9aUv5LpWcIu/e+ZXTsVLVXLsmDpVv/k9fe1tyhlQPgdCAg/Iwn+xF3YVvLEpfhrXrkcKFK0snn242NbJk4aTcY28O+XHyJn7lmsbu/BSao7cqtbwJsFNCVo+e23KUkBoenw3LMQ2lyle9AfLyD10JIR5beozyt6pxxPDjnBXx8zlxhA0dPryQkm5O/+fiJd3gidzJmZZuVr8i20DaBoM3RnDhF0uccgDsbbM0N9KkEO1JXco22NGeBveKtkMOQaNy7i1QIHIFafkcyP9CStz8swsaWk5WaSEyr7ysiKpZlYE6tyaHPW2h4/uG/NfrOi6PXzPE4d90oyOeVIC28Obxse3aVRTw== + access_key_secret: AgCE8EHoWhZm4q25TcXlMy65uPopUNULeyw1Z+reSAr3pDaT+9B2k8TkPyo8vwCLYykqQqPS3VV7X6J80upVGWbYBVUM/7kI3W6F1kRl5eQjDmkAUmFa0t2EAxQP7TN1VPHVLZGUhwTGXjARdDGgDHi/We7jhl781ZFIZ8G0nkWCSZrB4T4XI+Mb154nR+GMejrstjzhFdueWgFZX/wX3PmcbmI+eAu0yeiW9IWikmDTrQyv1P46dDyPAKquZc7Dbgy4AxJ/ebeQ4558sOW9hvhTxoQ0hrEezeOMAbzQKqPd2Y5470LxMtoGL+FNqbLHTBQnqSucyDzOO2hiFhnUaCPvpCE/TRT7T3NbQ8uaugYaRR3eNa3w9ILWduMQ2yDsG+cNrYHXcyoUtdAQQ1eRv11jFYFVARRRGuGiFzWsLmMDvokCxQgkYpJXj5HqeZ+oT2xBVgd7P+c6ZQXRzfuwUXTUh+w3QxZ4XrqBq1jv7RRnu+uCj3E+vaavqIS8ipYXfLzjneHFhlAm9GS3rAIbCPlrZCaIIe/r4KRjtP7Gj4f6jhaN5Xo5jvBPqLYfX/RY8fll9XJAZGH6a9k+NDcxrwiV/UBDEQcPgnx83bCuFQ/qvIdd3tnOZ2dIvEHXnLMfBYOd0OyvkC3CoGKgmf4d6x4xvrzyqRHSIBxOGvDMG54IutZwHngFEuQbtGgtD0eN/SsLRO4wcuDugYVgiSPCHQ+IONUqvj7c7IJgRQKad2oxmlP7ZzSExVV8 + bucketnames: AgDA2DCtrPQmcdJ/QTBNZgmf2C7VSE96LVwje8J1N9XbmTte/d0oO9V0vUanXRKdraISTlHWBRBrYOxKx42nZMVzxKOHUCBMrdSN2z9ytgxNMhX2XNusTd4oDucsW+KM4IZyg95CXNvOSt01Y/uwdnJNK71VaiCSM1Sp+lIgVBzkwiase/YitOmCXVBofVLubWtsVwIGy5cWMmNhWmD0fjG5aIQ0Nx3OjYq/tIsrM4iB7FOn9Us1PQ9bkUNqJKu3LZtNIklzgDEUY6+uwtULt/jh8bTGHdptG18D1tuBf1SmD/xIWeCHf5Btp7XgRjivBR45DDIZHyc5mNdM7ydNvmae8SgOrugBWACQ37ZYiRIivDHJDs6Aa0fWDDd4ntdYclix7SurmqLx+/wzp7nyNmF3rCJY0u3FyX7twmLO2xZyabfqIqPY+kiGlKBY8uLGkLSDXbaLF78Vkww8Q5m5qdOZklADB+VZyii2PyFxLodeOKWujdG7vFnCiI41hCj3ry1FFM8o6397GO2zL1j4bflsmYh+9c5YKgc3ykzbLnAl+G30A505uXpBLJuXmHHXayGTNzU0D3EtWKnEwXF5NRYRQTdBPrwmUo7ml/UU04bdvJGob9dxGjypjB9CQG9pL3ouGTZZ60kNnSodhnKbRFv+Z1P8oNi4Vz6789eOrLVdn5kRppZy0f231HVRKfCXKjTAw96v + endpoint: AgClXa9d4ePlMAN9w+JajdcDv+Kde3Zp90vgZ2RE3pGebMq4WNpIZ3hHZzUWQWS90ffhJmGsPrry14aGSkKyj+2i5pVLFjrMhRajOcWvQrWcdNa/2XrkijpSoGTM0wXm1yLgmfRZGnhgt5LFWjuiOFze8j984FseGWp7ZKGA86CSfiWFidcaUhzVUaPC4P/tdfQMHRnYq1GdFw/6TxZRvpoEW/RRm3P2B+H6nAyrjILpdOCEzvM88WiVF93IB/oQWw4HnRt92lQ0A2Ni81s/pTngIYhIyXS6KrWt9+0w131fJSdvC5TRidcYXVAllxRyKUm/2hEqEtCA+w3yMyQ7ZW6rEhqWAJrN0qlDzSQ3rmYzRMKWaXQVDxrMhqg6PkaYjuQYQRLmOWzJ+4KCgUXI1jPOce5W3KOGPwVJNUe7RDRrjep3fDn7XjFJoWJG76zzGkAYWsY2QkZ4LwnxzuAFFQ3iyLYw/KDnOGG3BZvIKCHDLhk31PCkrOZV4rlmm1RIPpSeZOmbBGYoM3vSvdXNmUxGzju2LL3mBF0O9OkgKozQO+ihCGVjHJMRvpB5mcoKvcP9g2+HidAwlEAt8igm5uFFx06OMnvv7RmI+kLpcgE+crA3W0L1gZKdxFZKNKxn+AFBxY5TrAoQpaSuGv8czGxuy/ZxLWF0fSKeyv4uCMWY1wq4eXT8QiyJbWYtBh9sqKF6pqNABeDNwg79y4sP8Z76PPJreN8Sy8kq06lQvDbk + template: + metadata: + name: loki-storage + namespace: openshift-logging + type: Opaque diff --git a/cluster-config/clusters/overlays/local.home/components/lvm-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/lvm-operator/kustomization.yaml new file mode 100644 index 0000000..142b99d --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/lvm-operator/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../../../../components/lvm-operator/overlays/standalone + +patches: + - patch: |- + - op: add + path: /spec/storage/deviceClasses/0/deviceSelector + value: + paths: + - /dev/nvme1n1 + target: + kind: LVMCluster diff --git a/cluster-config/clusters/overlays/local.home/components/node-config/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/node-config/kustomization.yaml new file mode 100644 index 0000000..ed4750c --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/node-config/kustomization.yaml @@ -0,0 +1,18 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - set-max-pods.yaml + - ../../../../../components/wake-on-lan/base + +patches: + - patch: | + - op: replace + path: /spec/config/systemd/units/0/name + value: wol@enp8s0.service + - op: add + path: /metadata/labels/machineconfiguration.openshift.io~1role + value: master + target: + kind: MachineConfig + name: 99-wol-service diff --git a/cluster-config/clusters/overlays/local.home/components/node-config/set-max-pods.yaml b/cluster-config/clusters/overlays/local.home/components/node-config/set-max-pods.yaml new file mode 100644 index 0000000..9c5ccf7 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/node-config/set-max-pods.yaml @@ -0,0 +1,12 @@ +apiVersion: machineconfiguration.openshift.io/v1 +kind: KubeletConfig +metadata: + name: set-max-pods +spec: + autoSizingReserved: true + machineConfigPoolSelector: + matchLabels: + pools.operator.machineconfiguration.openshift.io/master: "" + kubeletConfig: + podsPerCore: 11 + maxPods: 352 diff --git a/cluster-config/clusters/overlays/local.home/components/tenants/appset.yaml b/cluster-config/clusters/overlays/local.home/components/tenants/appset.yaml new file mode 100644 index 0000000..b5e4f1a --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/tenants/appset.yaml @@ -0,0 +1,29 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: tenants + namespace: openshift-gitops +spec: + generators: + - git: + directories: + - path: tenants/**/base + repoURL: https://github.com/gnunn-gitops/cluster-config + revision: main + goTemplate: true + syncPolicy: + preserveResourcesOnDeletion: true + template: + metadata: + name: tenant-{{ index .path.segments 1 | normalize }} + spec: + destination: + name: in-cluster + namespace: default + project: cluster-config + source: + path: '{{ .path.path }}' + repoURL: https://github.com/gnunn-gitops/cluster-config + syncPolicy: + automated: + selfHeal: true diff --git a/cluster-config/clusters/overlays/local.home/components/tenants/kustomization.yaml b/cluster-config/clusters/overlays/local.home/components/tenants/kustomization.yaml new file mode 100644 index 0000000..bfaf768 --- /dev/null +++ b/cluster-config/clusters/overlays/local.home/components/tenants/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - appset.yaml diff --git a/cluster-config/clusters/overlays/local.hub/README.md b/cluster-config/clusters/overlays/local.hub/README.md new file mode 100644 index 0000000..0a1a4f4 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/README.md @@ -0,0 +1,3 @@ +#### Home (local) Cluster + +This is my home cluster which runs on a server under my desk and uses the highly original cluster name of 'home'. It runs in libvirt on a Ryzen 3900x server with 128 GB of memory. It is typically configured as three combined master/worker nodes with 7 vCPU and 35 GB per node. diff --git a/cluster-config/clusters/overlays/local.hub/components/acs-operator/certificate.yaml b/cluster-config/clusters/overlays/local.hub/components/acs-operator/certificate.yaml new file mode 100644 index 0000000..cccabdd --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/acs-operator/certificate.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: central-tls-letsencrypt-cert + namespace: stackrox +spec: + # Replace default secret since ACS doesn't support referencing a different secret + secretName: central-default-tls-cert + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - central-stackrox.apps.hub.ocplab.com diff --git a/cluster-config/clusters/overlays/local.hub/components/acs-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/acs-operator/kustomization.yaml new file mode 100644 index 0000000..ea24419 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/acs-operator/kustomization.yaml @@ -0,0 +1,6 @@ +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +resources: +- ../../../../../components/acs-operator/overlays/aggregate +- certificate.yaml diff --git a/cluster-config/clusters/overlays/local.hub/components/consolelinks/acs-consolelink.yaml b/cluster-config/clusters/overlays/local.hub/components/consolelinks/acs-consolelink.yaml new file mode 100644 index 0000000..5f4344b --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/consolelinks/acs-consolelink.yaml @@ -0,0 +1,11 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: acs +spec: + href: 'https://central-stackrox.apps.hub.ocplab.com' + location: ApplicationMenu + text: Advanced Cluster Security + applicationMenu: + section: Red Hat Applications + imageURL: https://central-stackrox.apps.hub.ocplab.com/static/media/rh-favicon.0110fdfc5cab55416acf.ico diff --git a/cluster-config/clusters/overlays/local.hub/components/consolelinks/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/consolelinks/kustomization.yaml new file mode 100644 index 0000000..8f1ceb8 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/consolelinks/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../../components/consolelinks/base +- acs-consolelink.yaml diff --git a/cluster-config/clusters/overlays/local.hub/components/cost-management-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/cost-management-operator/kustomization.yaml new file mode 100644 index 0000000..72071cb --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/cost-management-operator/kustomization.yaml @@ -0,0 +1,15 @@ +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 + +namespace: costmanagement-metrics-operator + +bases: +- https://github.com/redhat-cop/gitops-catalog/cost-management-operator/overlays/aggregate + +patchesJson6902: + - path: patch-source-and-name.yaml + target: + group: costmanagement-metrics-cfg.openshift.io + kind: CostManagementMetricsConfig + name: config + version: v1beta1 diff --git a/cluster-config/clusters/overlays/local.hub/components/cost-management-operator/patch-source-and-name.yaml b/cluster-config/clusters/overlays/local.hub/components/cost-management-operator/patch-source-and-name.yaml new file mode 100644 index 0000000..6d55abb --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/cost-management-operator/patch-source-and-name.yaml @@ -0,0 +1,6 @@ +- op: replace + path: /spec/source/name + value: Hub +- op: replace + path: /metadata/name + value: hub-cluster diff --git a/cluster-config/clusters/overlays/local.hub/components/eso/doppler-push-secret-store.yaml b/cluster-config/clusters/overlays/local.hub/components/eso/doppler-push-secret-store.yaml new file mode 100644 index 0000000..251c676 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/eso/doppler-push-secret-store.yaml @@ -0,0 +1,13 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: doppler-push-secret +spec: + provider: + doppler: + auth: + secretRef: + dopplerToken: + name: eso-token-cluster-push-secret + key: dopplerToken + namespace: hub-secrets diff --git a/cluster-config/clusters/overlays/local.hub/components/eso/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/eso/kustomization.yaml new file mode 100644 index 0000000..cbb120a --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/eso/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- ../../../../../components/eso/overlays/aggregate +- doppler-push-secret-store.yaml diff --git a/cluster-config/clusters/overlays/local.hub/components/lokistack/README.md b/cluster-config/clusters/overlays/local.hub/components/lokistack/README.md new file mode 100644 index 0000000..4f269bb --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/lokistack/README.md @@ -0,0 +1,54 @@ + + +### Introduction + +Installs the Tech Preview LokiStack for cluster logging using local QNAP NAS for object storage. + +Installation is based on docs here: + +https://github.com/grafana/loki/blob/main/operator/docs/forwarding_logs_to_gateway.md#openshift-logging + +# Accessing logs + +You can access the logs using the logcli tool from grafana: + +https://github.com/grafana/loki/releases/tag/v2.5.0 + +Example queries: + +View raw application logs: +``` +export LOKI_ADDR=http://lokistack-openshift-logging.apps.home.ocplab.com/api/logs/v1/application +logcli --bearer-token="$(oc whoami -t)" query '{kubernetes_namespace_name="product-catalog-dev"}' +``` + +View applicatons logs textually without JSON: +``` +export LOKI_ADDR=http://lokistack-openshift-logging.apps.home.ocplab.com/api/logs/v1/application +logcli --bearer-token="$(oc whoami -t)" query '{kubernetes_namespace_name="product-catalog-dev", kubernetes_container_name="server"}' --output=raw | jq '."@timestamp",.kubernetes.pod_name,.level,.message' | paste - - - - +``` + +View infrastructure logs: +``` +export LOKI_ADDR=http://lokistack-openshift-logging.apps.home.ocplab.com/api/logs/v1/infrastructure +logcli --bearer-token="$(oc whoami -t)" query '{kubernetes_namespace_name="openshift-logging"}' +``` + +### Storage Secret + +You will need a storage secret for your S3 bucket for Loki to use, format of secret is as follows: + +``` +apiVersion: v1 +data: + access_key_id: XXXXXX + access_key_secret: XXXXXX + bucketnames: XXXXXX + endpoint: XXXXXXXXXXXX +kind: Secret +metadata: + name: loki-storage + namespace: openshift-logging +``` + +The sealed secret here is referencing Minio running on my QNAP NAS so non AWS S3 buckets do work fine. diff --git a/cluster-config/clusters/overlays/local.hub/components/lokistack/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/lokistack/kustomization.yaml new file mode 100644 index 0000000..c64c63b --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/lokistack/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../../components/loki/operator/cluster-logging/base +- ../../../../../components/loki/operator/loki/base +- ../../../../../components/loki/instance/overlays/sno +- loki-storage-qnap-secret.yaml diff --git a/cluster-config/clusters/overlays/local.hub/components/lokistack/loki-storage-qnap-secret.yaml b/cluster-config/clusters/overlays/local.hub/components/lokistack/loki-storage-qnap-secret.yaml new file mode 100644 index 0000000..82f08f0 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/lokistack/loki-storage-qnap-secret.yaml @@ -0,0 +1,16 @@ +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: loki-storage + namespace: openshift-logging +spec: + encryptedData: + access_key_id: AgADsXMtym0OLY598xcLZ4e6zPgh9x3KtCRX59K3J/LriPJPwNuMugAMZcHjLaA9nm+Rwqg095uhGD0pUxK5N336fMiMJ+7WpzMsR8nqMS3eoOtxhXBwML5wXqLmpf2FSxujUXws847JsohHtZiCg6ZBlWuJ2pEaCz6yPecMU8dixz+7OMs079origgakI0FjHlEPMn6BOhAOR4TMCt877mNmeLWrmxNEQt3ql4qMvNH3Ru8G4YijmO+jS9OQYqXYwTbO237zx+D3DDw0PAuUzqMIKXSZZdGNmATXIROu9+4TJGT6YnraMxON81F4t78D+y6reM6AIXN49SDcIxpmSZrtLJ5QQesOPbZ+x4mdR2Rj4RaqyktuNaBknn+CUCtx9aUv5LpWcIu/e+ZXTsVLVXLsmDpVv/k9fe1tyhlQPgdCAg/Iwn+xF3YVvLEpfhrXrkcKFK0snn242NbJk4aTcY28O+XHyJn7lmsbu/BSao7cqtbwJsFNCVo+e23KUkBoenw3LMQ2lyle9AfLyD10JIR5beozyt6pxxPDjnBXx8zlxhA0dPryQkm5O/+fiJd3gidzJmZZuVr8i20DaBoM3RnDhF0uccgDsbbM0N9KkEO1JXco22NGeBveKtkMOQaNy7i1QIHIFafkcyP9CStz8swsaWk5WaSEyr7ysiKpZlYE6tyaHPW2h4/uG/NfrOi6PXzPE4d90oyOeVIC28Obxse3aVRTw== + access_key_secret: AgCE8EHoWhZm4q25TcXlMy65uPopUNULeyw1Z+reSAr3pDaT+9B2k8TkPyo8vwCLYykqQqPS3VV7X6J80upVGWbYBVUM/7kI3W6F1kRl5eQjDmkAUmFa0t2EAxQP7TN1VPHVLZGUhwTGXjARdDGgDHi/We7jhl781ZFIZ8G0nkWCSZrB4T4XI+Mb154nR+GMejrstjzhFdueWgFZX/wX3PmcbmI+eAu0yeiW9IWikmDTrQyv1P46dDyPAKquZc7Dbgy4AxJ/ebeQ4558sOW9hvhTxoQ0hrEezeOMAbzQKqPd2Y5470LxMtoGL+FNqbLHTBQnqSucyDzOO2hiFhnUaCPvpCE/TRT7T3NbQ8uaugYaRR3eNa3w9ILWduMQ2yDsG+cNrYHXcyoUtdAQQ1eRv11jFYFVARRRGuGiFzWsLmMDvokCxQgkYpJXj5HqeZ+oT2xBVgd7P+c6ZQXRzfuwUXTUh+w3QxZ4XrqBq1jv7RRnu+uCj3E+vaavqIS8ipYXfLzjneHFhlAm9GS3rAIbCPlrZCaIIe/r4KRjtP7Gj4f6jhaN5Xo5jvBPqLYfX/RY8fll9XJAZGH6a9k+NDcxrwiV/UBDEQcPgnx83bCuFQ/qvIdd3tnOZ2dIvEHXnLMfBYOd0OyvkC3CoGKgmf4d6x4xvrzyqRHSIBxOGvDMG54IutZwHngFEuQbtGgtD0eN/SsLRO4wcuDugYVgiSPCHQ+IONUqvj7c7IJgRQKad2oxmlP7ZzSExVV8 + bucketnames: AgDA2DCtrPQmcdJ/QTBNZgmf2C7VSE96LVwje8J1N9XbmTte/d0oO9V0vUanXRKdraISTlHWBRBrYOxKx42nZMVzxKOHUCBMrdSN2z9ytgxNMhX2XNusTd4oDucsW+KM4IZyg95CXNvOSt01Y/uwdnJNK71VaiCSM1Sp+lIgVBzkwiase/YitOmCXVBofVLubWtsVwIGy5cWMmNhWmD0fjG5aIQ0Nx3OjYq/tIsrM4iB7FOn9Us1PQ9bkUNqJKu3LZtNIklzgDEUY6+uwtULt/jh8bTGHdptG18D1tuBf1SmD/xIWeCHf5Btp7XgRjivBR45DDIZHyc5mNdM7ydNvmae8SgOrugBWACQ37ZYiRIivDHJDs6Aa0fWDDd4ntdYclix7SurmqLx+/wzp7nyNmF3rCJY0u3FyX7twmLO2xZyabfqIqPY+kiGlKBY8uLGkLSDXbaLF78Vkww8Q5m5qdOZklADB+VZyii2PyFxLodeOKWujdG7vFnCiI41hCj3ry1FFM8o6397GO2zL1j4bflsmYh+9c5YKgc3ykzbLnAl+G30A505uXpBLJuXmHHXayGTNzU0D3EtWKnEwXF5NRYRQTdBPrwmUo7ml/UU04bdvJGob9dxGjypjB9CQG9pL3ouGTZZ60kNnSodhnKbRFv+Z1P8oNi4Vz6789eOrLVdn5kRppZy0f231HVRKfCXKjTAw96v + endpoint: AgClXa9d4ePlMAN9w+JajdcDv+Kde3Zp90vgZ2RE3pGebMq4WNpIZ3hHZzUWQWS90ffhJmGsPrry14aGSkKyj+2i5pVLFjrMhRajOcWvQrWcdNa/2XrkijpSoGTM0wXm1yLgmfRZGnhgt5LFWjuiOFze8j984FseGWp7ZKGA86CSfiWFidcaUhzVUaPC4P/tdfQMHRnYq1GdFw/6TxZRvpoEW/RRm3P2B+H6nAyrjILpdOCEzvM88WiVF93IB/oQWw4HnRt92lQ0A2Ni81s/pTngIYhIyXS6KrWt9+0w131fJSdvC5TRidcYXVAllxRyKUm/2hEqEtCA+w3yMyQ7ZW6rEhqWAJrN0qlDzSQ3rmYzRMKWaXQVDxrMhqg6PkaYjuQYQRLmOWzJ+4KCgUXI1jPOce5W3KOGPwVJNUe7RDRrjep3fDn7XjFJoWJG76zzGkAYWsY2QkZ4LwnxzuAFFQ3iyLYw/KDnOGG3BZvIKCHDLhk31PCkrOZV4rlmm1RIPpSeZOmbBGYoM3vSvdXNmUxGzju2LL3mBF0O9OkgKozQO+ihCGVjHJMRvpB5mcoKvcP9g2+HidAwlEAt8igm5uFFx06OMnvv7RmI+kLpcgE+crA3W0L1gZKdxFZKNKxn+AFBxY5TrAoQpaSuGv8czGxuy/ZxLWF0fSKeyv4uCMWY1wq4eXT8QiyJbWYtBh9sqKF6pqNABeDNwg79y4sP8Z76PPJreN8Sy8kq06lQvDbk + template: + metadata: + name: loki-storage + namespace: openshift-logging + type: Opaque diff --git a/cluster-config/clusters/overlays/local.hub/components/lvm-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/lvm-operator/kustomization.yaml new file mode 100644 index 0000000..5d70ddd --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/lvm-operator/kustomization.yaml @@ -0,0 +1,12 @@ +resources: +- ../../../../../components/lvm-operator/base + +patches: + - patch: |- + - op: add + path: /spec/storage/deviceClasses/0/deviceSelector + value: + paths: + - /dev/nvme0n1p5 + target: + kind: LVMCluster diff --git a/cluster-config/clusters/overlays/local.hub/components/nmstate/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/nmstate/kustomization.yaml new file mode 100644 index 0000000..5773560 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/nmstate/kustomization.yaml @@ -0,0 +1,19 @@ +resources: +- github.com/redhat-cop/gitops-catalog/nmstate/aggregate/overlays/default +- node-network-configuration-policy.yaml + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: "stable" + target: + kind: Subscription + name: kubernetes-nmstate-operator + - patch: |- + - op: add + path: /metadata/annotations/argocd.argoproj.io~1sync-options + value: SkipDryRunOnMissingResource=true + target: + kind: NMState + name: nmstate diff --git a/cluster-config/clusters/overlays/local.hub/components/nmstate/node-network-configuration-policy.yaml b/cluster-config/clusters/overlays/local.hub/components/nmstate/node-network-configuration-policy.yaml new file mode 100644 index 0000000..30dfbdd --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/nmstate/node-network-configuration-policy.yaml @@ -0,0 +1,68 @@ +apiVersion: nmstate.io/v1 +kind: NodeNetworkConfigurationPolicy +metadata: + name: hub-server + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + desiredState: + interfaces: + - name: enp0s31f6 + state: absent + type: ethernet + ipv4: + dhcp: true + enabled: true + auto-dns: true + + # interfaces: + # - name: bond0 + # description: Bond with ports enp4s0 and enp0s31f6 + # type: bond + # state: up + # copy-mac-from: enp4s0 + # ipv4: + # dhcp: false + # enabled: true + # link-aggregation: + # mode: active-backup + # options: + # miimon: '140' + # port: + # - enp4s0 + # - enp0s31f6 + # mtu: 1450 + # - name: br1 + # description: Linux bridge with bond0 as a port + # type: linux-bridge + # state: up + # mtu: 9000 + # ipv4: + # enabled: false + # bridge: + # options: + # stp: + # enabled: false + # port: + # - name: bond0 + + # interfaces: + # - name: enp4s0 + # state: up + # type: ethernet + # ipv4: + # dhcp: false + # enabled: true + # - name: enp0s31f6 + # state: up + # type: ethernet + # ipv4: + # dhcp: true + # enabled: true + # auto-dns: true + # routes: + # config: + # - destination: 0.0.0.0/0 + # next-hop-address: 192.168.1.1 + # next-hop-interface: enp4s0 + # table-id: 254 diff --git a/cluster-config/clusters/overlays/local.hub/components/node-config/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/node-config/kustomization.yaml new file mode 100644 index 0000000..6888903 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/node-config/kustomization.yaml @@ -0,0 +1,15 @@ +resources: +- set-max-pods.yaml +- ../../../../../components/wake-on-lan/base + +patches: + - patch: | + - op: replace + path: /spec/config/systemd/units/0/name + value: wol@enp0s31f6.service + - op: add + path: /metadata/labels/machineconfiguration.openshift.io~1role + value: master + target: + kind: MachineConfig + name: 99-wol-service diff --git a/cluster-config/clusters/overlays/local.hub/components/node-config/set-max-pods.yaml b/cluster-config/clusters/overlays/local.hub/components/node-config/set-max-pods.yaml new file mode 100644 index 0000000..d3f0b24 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/node-config/set-max-pods.yaml @@ -0,0 +1,12 @@ +apiVersion: machineconfiguration.openshift.io/v1 +kind: KubeletConfig +metadata: + name: set-max-pods +spec: + autoSizingReserved: true + machineConfigPoolSelector: + matchLabels: + pools.operator.machineconfiguration.openshift.io/master: "" + kubeletConfig: + podsPerCore: 10 + maxPods: 450 diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/README.md b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/README.md new file mode 100644 index 0000000..d260b29 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/README.md @@ -0,0 +1 @@ +Note you need to manually generate the config bundle secret in the generate folder, at some point I'll fully gitops this process. diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/config-bundle-secret-qnap.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/config-bundle-secret-qnap.yaml new file mode 100644 index 0000000..61e3b93 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/config-bundle-secret-qnap.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +data: + config.yaml: RVhURVJOQUxfVExTX1RFUk1JTkFUSU9OOiBmYWxzZQpTRVJWRVJfSE9TVE5BTUU6IHJlZ2lzdHJ5LmFwcHMuaG9tZS5vY3BsYWIuY29tClBSRUZFUlJFRF9VUkxfU0NIRU1FOiBodHRwcwpESVNUUklCVVRFRF9TVE9SQUdFX0NPTkZJRzoKICAgIHJhZG9zR1dTdG9yYWdlOgogICAgICAgIC0gUmFkb3NHV1N0b3JhZ2UKICAgICAgICAtIGFjY2Vzc19rZXk6IDc0RzI1S1FBSVhaWDlISEtDUTc2CiAgICAgICAgICBzZWNyZXRfa2V5OiB4ZzVKd0gzUzY3TytzSytOTk1wOHFxdHFFekhJZ3dSRGhmVjdESmVsCiAgICAgICAgICBidWNrZXRfbmFtZTogcXVheQogICAgICAgICAgaG9zdG5hbWU6IGxhYi1uYXMub2NwbGFiLmNvbQogICAgICAgICAgaXNfc2VjdXJlOiB0cnVlCiAgICAgICAgICBwb3J0OiA5MDAwCiAgICAgICAgICBzdG9yYWdlX3BhdGg6IC9kYXRhc3RvcmFnZS9yZWdpc3RyeQpESVNUUklCVVRFRF9TVE9SQUdFX0RFRkFVTFRfTE9DQVRJT05TOiBbXQpESVNUUklCVVRFRF9TVE9SQUdFX1BSRUZFUkVOQ0U6CiAgICAtIHJhZG9zR1dTdG9yYWdlClNTT19MT0dJTl9DT05GSUc6CiAgQ0xJRU5UX0lEOiBxdWF5CiAgQ0xJRU5UX1NFQ1JFVDogNzIzNzgyYmEtOTVkNC00ZDk1LThiMDQtZWZlYmNlMGFkZjg2CiAgT0lEQ19TRVJWRVI6IGh0dHBzOi8vc3NvLXNzby5hcHBzLmhvbWUub2NwbGFiLmNvbS9hdXRoL3JlYWxtcy9vcGVuc2hpZnQvCiAgTE9HSU5fU0NPUEVTOgogICAgLSBvcGVuaWQKICBTRVJWSUNFX05BTUU6IE9wZW5TaGlmdApTVVBFUl9VU0VSUzoKICAgIC0gYWRtaW4KICAgIC0gcXVheWFkbWluCkZFQVRVUkVfRElSRUNUX0xPR0lOOiB0cnVlCkZFQVRVUkVfVVNFUl9JTklUSUFMSVpFOiB0cnVl + ssl.cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdpakNDQkhLZ0F3SUJBZ0lSQU5DY3FxS0dWdXVORjBDcDJDVUI0eGN3RFFZSktvWklodmNOQVFFTUJRQXcKU3pFTE1Ba0dBMVVFQmhNQ1FWUXhFREFPQmdOVkJBb1RCMXBsY205VFUwd3hLakFvQmdOVkJBTVRJVnBsY205VApVMHdnVWxOQklFUnZiV0ZwYmlCVFpXTjFjbVVnVTJsMFpTQkRRVEFlRncweU1qRXdNRFF3TURBd01EQmFGdzB5Ck16QXhNREl5TXpVNU5UbGFNQ2d4SmpBa0JnTlZCQU1USFhKbFoybHpkSEo1TG1Gd2NITXVhRzl0WlM1dlkzQnMKWVdJdVkyOXRNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTdTQW1QeUpnWjVyaApLbmkwRUFzME1qaXI4b0habFlaTm1WaFBHVWhXVXJwQlM0ejRTa2RuWmdZUHVEdE81UVFQZVZ2ZXAyU094cFd0CjFkRm91Z1NES0ljcm9laTUxTmh4TjV6RlZhL1hmR25kaUFpYnFMYVMxS2ZJc0dJZ05zV1dpcWI1NmdxMjVOTE0KUk8yeXdZRzVxUFNXeTM3R1dMSFEvRkpqKy8vWGZCcUtuMzhSU29tZVRjbkg2ZVJxM0dwUjNlSmNsbUluV1V2Twozbmw0NE9WTVZWcHcweVFOU3plVFVNcEVNNzJMU1lFUkhZUS9EUkdlbVdCaDVQQ2gzT00xdlhtbFBDUVZZd2E3CnQ1bUNjdHh3UUgyS0o0UC80UVJxREdIZlcwc1E5ZW4xTWtEb3c2WU83WVFTT1h5UC9IcjVvTXpEcXFGT0R5OXcKbEFPdlRiUXBRUUlEQVFBQm80SUNpakNDQW9Zd0h3WURWUjBqQkJnd0ZvQVV5Tmw0YUtMWkdXalZQWExlWHdvKwozTFdHaHFZd0hRWURWUjBPQkJZRUZFcUd3c2h5R3pVL1JWZVVRa1JiNHhJeC9HYzhNQTRHQTFVZER3RUIvd1FFCkF3SUZvREFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0QKQWpCSkJnTlZIU0FFUWpCQU1EUUdDeXNHQVFRQnNqRUJBZ0pPTUNVd0l3WUlLd1lCQlFVSEFnRVdGMmgwZEhCegpPaTh2YzJWamRHbG5ieTVqYjIwdlExQlRNQWdHQm1lQkRBRUNBVENCaUFZSUt3WUJCUVVIQVFFRWZEQjZNRXNHCkNDc0dBUVVGQnpBQ2hqOW9kSFJ3T2k4dmVtVnliM056YkM1amNuUXVjMlZqZEdsbmJ5NWpiMjB2V21WeWIxTlQKVEZKVFFVUnZiV0ZwYmxObFkzVnlaVk5wZEdWRFFTNWpjblF3S3dZSUt3WUJCUVVITUFHR0gyaDBkSEE2THk5NgpaWEp2YzNOc0xtOWpjM0F1YzJWamRHbG5ieTVqYjIwd2dnRUZCZ29yQmdFRUFkWjVBZ1FDQklIMkJJSHpBUEVBCmR3Q3Q5Nzc2ZlA4UXlJdWRQWndlUGhocXRHY3BYYyt4RENUS2hZWTA2OXlDaWdBQUFZT2ozTnpjQUFBRUF3QkkKTUVZQ0lRQ1IzME80MHd6ZlZIdEZtVkFHY2hJK1ZyMzl1aVpuQlhUTE8vQ0d2c1NpMlFJaEFLMExKSnR4UzkrVgpRS0pnZjlVTkZKRFdxWkJ6MHNySmI4TS91d2l2WUl6VEFIWUFlaktNVk5pM0xiWWc2ampnVWg3cGhCWndNaE9GClRUdlNLOEU2VjZOUzYxSUFBQUdEbzl6YzlRQUFCQU1BUnpCRkFpQUtob2tFNmFady9haHZtb0pTdEJJUVBOWFIKdEZwMGpJNlczTVB5V1JpenNBSWhBUDRsTWdQaHprL1lXOE9QMXRGMEFhS0VHaHJiYmtkQkhQVGYreGIwRWpiYwpNQ2dHQTFVZEVRUWhNQitDSFhKbFoybHpkSEo1TG1Gd2NITXVhRzl0WlM1dlkzQnNZV0l1WTI5dE1BMEdDU3FHClNJYjNEUUVCREFVQUE0SUNBUUFZOU5aa0RGWXMvUlB5WmtuSm9RVjZJU1hwMkFZWnk0U2F4dkNZS2dKVzFPSTUKc1JWdUp4OS80MmVEWE1Dbm5RQkNHQ3FPYmw3OHNCazZndC9Wa0ZISG8yRkdac3hXQVAzOUFqM1ZrOFNJTlc1bQo0QTBxT1RJK1JpMFArZUY5U1E1aGpodjJkaWVEcEVjTEUxMERCcDdvQ0Q4Vm1XVFNuZGllZVloMG9xaURKSVhDClc5NEpoRWptZy9xVkNoZThSUVNiQ1RXYm9HeUthZXlVT3JMM0hSZW16QUhab1VtN01qc1ZjUXYyT1RzTGM3RzYKdkYxSy9NUFpISEFHL1NLMUhPM3FlNVZaZFZIS2RybE1GR0ZSRjZ0U0pSUUwxTzZLbVc4Zk1MYlpCWkhqWS92ZQpTS3k1WUdTR0VHY2ptQjA3UDdabndMTGl5MWtFeDR5NnN2NTVZL3ZUYWlJaVV1SkNDQ2NVb25qQ0hwUU1ZTnl0Cms0UGV3MUdZQjdMV2J0VGhZTzJLRkFxbjFtRHUzZXd5TkdWMXdaeXM4c2ROYVRxOFJPdHVyR1VkS3pxSU11VzUKdXllYlcrWFNIblduajZOaGRqYkt0RlpPM2JuM0pCcmVqaFhwcnd4ZzQ4dmk0cmRFVDlsYm1hVmZoY3g2LzUyagpSbkN2cEdyeTE2bVhqNmM1OEdieFdTWTdNek1TYytHK0UzL3VwZXpacTg3aU1KVjRIcFVlT2NsRHF4ZExrcTg0Clpxb2QxT0tSdDNvWkNjR0o0aHVoV3FhaGx5L3Nmck1PRjhIdmhIRXlNdE1HZVNuQm13WU1Qc1poeEpQMXNMWHEKUGUyV052UUErSmsvOXlMQTR1UnRDOVVjck9iaDJVcU9WNjNJMCtLUUZYWnpFbUpNb0k2aU1FZDFCekxpSmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlHMVRDQ0JMMmdBd0lCQWdJUWJGV3IyOUFIa3NlZEJ3ellFWjdXdnpBTkJna3Foa2lHOXcwQkFRd0ZBRENCCmlERUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdUQ2s1bGR5QktaWEp6WlhreEZEQVNCZ05WQkFjVEMwcGwKY25ObGVTQkRhWFI1TVI0d0hBWURWUVFLRXhWVWFHVWdWVk5GVWxSU1ZWTlVJRTVsZEhkdmNtc3hMakFzQmdOVgpCQU1USlZWVFJWSlVjblZ6ZENCU1UwRWdRMlZ5ZEdsbWFXTmhkR2x2YmlCQmRYUm9iM0pwZEhrd0hoY05NakF3Ck1UTXdNREF3TURBd1doY05NekF3TVRJNU1qTTFPVFU1V2pCTE1Rc3dDUVlEVlFRR0V3SkJWREVRTUE0R0ExVUUKQ2hNSFdtVnliMU5UVERFcU1DZ0dBMVVFQXhNaFdtVnliMU5UVENCU1UwRWdSRzl0WVdsdUlGTmxZM1Z5WlNCVAphWFJsSUVOQk1JSUNJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBaG1semZxTzFNZGdqCjRXM2RwQlBUVkJYMUF1dmNBeUcxZmwwZFVudy9NZXVlQ1d6UldUaGVaMzVMVm85MWtMSTNERFZhWktXK1RCQXMKSkJqRWJZbU13Y1dTVFdZQ2c1MzM0U0YwK2N0REFzRnhzWCtyVERoOWtTckcvNG1wNk9TaHViTGFFSVVKaVpvNAp0ODczVHVTZDBXajVEV3QzRHRwQUc4VDM1bC92K3hyTjh1YjhQU1NvWDVWa2d3K2pXZjRLUXROdlVGTERxOG1GCldoVW5QTDZqSEFBRFhwdnM0bFROWXdPdHg5eVF0YnB4d1N0N1FKWTErSUNybVJKQjZCdUtSdC9qZkRKRjlKc2MKUlFWbEhJeFFkS0FKbDdvYVZuWGdEa3F0azJxZGRkM2tDRFhkNzRndjgxM0c5MXo3Q2pzR3lKOTNvSklsTlMzVQpnRmJENlY1NEpNZ1ozclNtb3RZYno5OG9aeFg3TUtidENtMWFKL3EraFR2MllLMXlNeHJuZmNpZUttT1lCYkZECmhuVzVPNlJNQTcwM2RCSzkyajZYUk4yRXR0TGtRdXVqWmd5K2pYUkt0YVdNSWxrTmtXSm1PaUhtRXJRbmdIdnQKaU5rSWNqSnVtcTFkZEZYNGlhVEk0MGE2emd2SUJ0eEZlRHMyUmZjYUg3M2VyN2N0TlVVcWdRVDVyRmdKaE1tRgp4NzZyUWdCNU9aVWtvZGI1azJleDdQK0d1NEo4NmJTMTUwOTRVdVljVjA5aFZla25tVGg1RXg5Q0JLaXBMUzJXCjJ3S0Jha2YrYVZZbk5DVTZTMG5BU3F0MnhyWnBHQzF2N3Y2RGh1ZXB5eUp0bjNxU1YyUG9CaVU1U3FsK2FBUnAKd1VpYlFNR200NGdqeU5EcURsVnArU2hMUWxVSDl4OENBd0VBQWFPQ0FYVXdnZ0Z4TUI4R0ExVWRJd1FZTUJhQQpGRk41djFxcUswclBWSURoMkp2QW5mS3lBMmJMTUIwR0ExVWREZ1FXQkJUSTJYaG9vdGtaYU5VOWN0NWZDajdjCnRZYUdwakFPQmdOVkhROEJBZjhFQkFNQ0FZWXdFZ1lEVlIwVEFRSC9CQWd3QmdFQi93SUJBREFkQmdOVkhTVUUKRmpBVUJnZ3JCZ0VGQlFjREFRWUlLd1lCQlFVSEF3SXdJZ1lEVlIwZ0JCc3dHVEFOQmdzckJnRUVBYkl4QVFJQwpUakFJQmdabmdRd0JBZ0V3VUFZRFZSMGZCRWt3UnpCRm9FT2dRWVkvYUhSMGNEb3ZMMk55YkM1MWMyVnlkSEoxCmMzUXVZMjl0TDFWVFJWSlVjblZ6ZEZKVFFVTmxjblJwWm1sallYUnBiMjVCZFhSb2IzSnBkSGt1WTNKc01IWUcKQ0NzR0FRVUZCd0VCQkdvd2FEQS9CZ2dyQmdFRkJRY3dBb1l6YUhSMGNEb3ZMMk55ZEM1MWMyVnlkSEoxYzNRdQpZMjl0TDFWVFJWSlVjblZ6ZEZKVFFVRmtaRlJ5ZFhOMFEwRXVZM0owTUNVR0NDc0dBUVVGQnpBQmhobG9kSFJ3Ck9pOHZiMk56Y0M1MWMyVnlkSEoxYzNRdVkyOXRNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFWRHdvSXpRRFYKZXJjVDBlWXFaakJOSjhWTld3VkZsUU90WkVScW41aVduRVZhTFpaZHp4bGJ2ejJGeDBFeFVOdVVFZ1lrSVZNNApZb2NLa0NRN2hPNW5vaWNvcS9EckVZSDVJdU5jdVcxSThKSlo5REx1QjFmWXZJSGxaMkpHNDZpTmJWS0EzeWdBCkV6ODZSdkRRbHQyQzQ5NHFxUFZJdFJqcno5WWxKRUdUMERydHR5QXBxMFlMRkR6ZitaMXBrTWhoN2MrN2ZYZUoKcW1JaGZKcGR1S2M4SEVRa1lRUVNoZW40MjZTM0gwSnJJQWJLY0JDaXlZRnVPaGZ5dnV3VkNGRGZGdnJqQURqZAo0algxdVFYZDE2MUl5RlJibTg5czJPajVvVTF3RFl6NXN4K2hvQ3VoNmxTcysvdVB1V29tSXEzeTFHREZOYWZXCitMc0hCVTE2bFFvNVEyeWgyNWxhUXNLUmd5UG1NcEhKOThlZG02eTJzSFVhYkFTbVJIeHZHaXV3d0UyNWFEVTAKMlNBZWVweUltSjJDekI4MFlHN1d4bHluSHFOaHBFN3hmQzdQelFsTGdtZkVIZFUrdEhGZVFhelJRbnJGa1cyVwprcVJHSXE3Y0tSbnl5cHZqUE1ramVpVjlsUmRBTTlmU0p2c0Izc3ZVdXUxY29JRzF4eEkxeWVnb0dNNHI1UVA0ClJHSVZ2WWFpSTc2QzBkam9TYlEvZGtJVVVYUXVCOEFMNWp5SDM0ZzNCWmFhWHl2cG1uVjRpbHBwTVhWQW5BWUcKT041MVdoSjZXMHhOZE5Kd3pZQVNaWUgrdG1DV0krTjYwR3YyTk5NR0h3TVo3ZTliWGd6VUNaSDVGYUJGREdSNQpTOVZXcUhCNzNRK095SVZ2SWJLWWNTYzJ3L2FTdUZLR1NBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRmdUQ0NCR21nQXdJQkFnSVFPWEpFT3ZraXQxSFgwMndRM1RFMWxUQU5CZ2txaGtpRzl3MEJBUXdGQURCNwpNUXN3Q1FZRFZRUUdFd0pIUWpFYk1Ca0dBMVVFQ0F3U1IzSmxZWFJsY2lCTllXNWphR1Z6ZEdWeU1SQXdEZ1lEClZRUUhEQWRUWVd4bWIzSmtNUm93R0FZRFZRUUtEQkZEYjIxdlpHOGdRMEVnVEdsdGFYUmxaREVoTUI4R0ExVUUKQXd3WVFVRkJJRU5sY25ScFptbGpZWFJsSUZObGNuWnBZMlZ6TUI0WERURTVNRE14TWpBd01EQXdNRm9YRFRJNApNVEl6TVRJek5UazFPVm93Z1lneEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BPWlhjZ1NtVnljMlY1Ck1SUXdFZ1lEVlFRSEV3dEtaWEp6WlhrZ1EybDBlVEVlTUJ3R0ExVUVDaE1WVkdobElGVlRSVkpVVWxWVFZDQk8KWlhSM2IzSnJNUzR3TEFZRFZRUURFeVZWVTBWU1ZISjFjM1FnVWxOQklFTmxjblJwWm1sallYUnBiMjRnUVhWMAphRzl5YVhSNU1JSUNJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBZ0JKbEZ6WU93OXNJCnM5Q3NWdzEyN2MwbjAweXRVSU5oNHFvZ1RRa3RaQW5jem9tZnpEMnA3UGJQd2R6eDA3SFdlemNvRVN0SDJqbkcKdkRvWnRGK212WDJkbzJOQ3RuYnlxVHNya2ZqaWI5RHNGaUNRQ1Q3aTZIVEpHTFNSMUdKazIzK2pCdkdJR0dxUQpJank4L2hQd2h4Ujc5dVFmanRUa1VjWVJaMFlJVWN1R0ZGUS92RFArZm15Yy94YWRHTDFSampXbXAyYkljbWZiCklXYXgxSnQ0QThCUU91ak04Tnk4bmt6K3J3V1dOUjlYV3JmL3p2azl0eXkyOWxUZHlPY1NPazJ1VElxM1hKcTAKdHlBOXluOGlOSzUrTzJobUFVVG5BVTVHVTVzellQZVV2bE0za0hORDh6TERVKy9icXY1MFRtbkhhNHhnazk3RQp4d3pmNFRLdXpKTTdVWGlWWjR2dVBWYitETkJwRHhzUDh5VW1hek50OTI1SCtuTkQ1WDRPcFdheEtYd3loR05WCmljUU53Wk5VTUJrVHJOTjlONmZyWFRwc05WemJRZGNTMnFsSkM5L1lnSW9KazJLT3RXYlBKWWpOaExpeFA2UTUKRDlrQ251c1NUSlY4ODJzRnFWNFdnOHk0WitMb0U1M01XNExUVExQdFcvL2U1WE9zSXpzdEFMODFWWFFKU2RoSgpXQnAva2pibVVaSU84eVo5SEUwWHZNbnNReWJRdjBGZlFLbEVSUFNaNTFlSG5sQWZWMVNvUHYxMFl5K3hVR1VKCjVsaENMa01hVExUd0pVZForZ1FlazlRbVJrcFFnYkxldm5pMy9HY1Y0Y2xYaEI0UFk5YnBZcnJXWDFVdTZsekcKS0FnRUpUbTREaXVwOGt5WEhBYy9EVkwxN2U4dmdnOENBd0VBQWFPQjhqQ0I3ekFmQmdOVkhTTUVHREFXZ0JTZwpFUW9qUHBieEIremlyeW52Z3FWLzBEQ2t0REFkQmdOVkhRNEVGZ1FVVTNtL1dxb3JTczlVZ09IWW04Q2Q4cklEClpzc3dEZ1lEVlIwUEFRSC9CQVFEQWdHR01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0VRWURWUjBnQkFvd0NEQUcKQmdSVkhTQUFNRU1HQTFVZEh3UThNRG93T0tBMm9EU0dNbWgwZEhBNkx5OWpjbXd1WTI5dGIyUnZZMkV1WTI5dApMMEZCUVVObGNuUnBabWxqWVhSbFUyVnlkbWxqWlhNdVkzSnNNRFFHQ0NzR0FRVUZCd0VCQkNnd0pqQWtCZ2dyCkJnRUZCUWN3QVlZWWFIUjBjRG92TDI5amMzQXVZMjl0YjJSdlkyRXVZMjl0TUEwR0NTcUdTSWIzRFFFQkRBVUEKQTRJQkFRQVloMUhjZENFOW5JcmdKN2N6MEM3TTdQRG15MTRSM2lKdm0zV09ubkwrNU5iK3FoK2NsaTN2QTBwKwpydlNOYjNJOFF6dkFQK3U0MzF5cXFjYXU4dnpZN3FON1EvYUdObndVNE0zMDl6LyszcmkwaXZDUmx2NzlRMlIrCi9jelNBYUY5ZmZnWkdjbENLeE8vV0l1NnBLSm1CSGFJa1U0TWlSVE9vazNKTXJPNjZCUWF2SEh4Vy9CQkM1Z0EKQ2lJREVPVU1zZm5Oa2pjWjdUdng1RHEyK1VVVEpuV3Z1NnJ2UDN0M085TEVBcEU5R1FEVEYxdzUyejk3R0ExRgp6Wk9GbGk5ZDMxa1dUejlSdmRWRkdEL3RTbzdvQm1GMEl4YTFEVkJ6SjBSSGZ4QmRpU3ByaFRFVXhPaXBha3lBCnZHcDR6N2gvam5aeW1ReWQvdGVSQ0JhaG8xK1YKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + ssl.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBN1NBbVB5SmdaNXJoS25pMEVBczBNamlyOG9IWmxZWk5tVmhQR1VoV1VycEJTNHo0ClNrZG5aZ1lQdUR0TzVRUVBlVnZlcDJTT3hwV3QxZEZvdWdTREtJY3JvZWk1MU5oeE41ekZWYS9YZkduZGlBaWIKcUxhUzFLZklzR0lnTnNXV2lxYjU2Z3EyNU5MTVJPMnl3WUc1cVBTV3kzN0dXTEhRL0ZKaisvL1hmQnFLbjM4UgpTb21lVGNuSDZlUnEzR3BSM2VKY2xtSW5XVXZPM25sNDRPVk1WVnB3MHlRTlN6ZVRVTXBFTTcyTFNZRVJIWVEvCkRSR2VtV0JoNVBDaDNPTTF2WG1sUENRVll3YTd0NW1DY3R4d1FIMktKNFAvNFFScURHSGZXMHNROWVuMU1rRG8KdzZZTzdZUVNPWHlQL0hyNW9NekRxcUZPRHk5d2xBT3ZUYlFwUVFJREFRQUJBb0lCQVFEV1FGa3ViRklzNm8wTwpRZmQ0RTVkNjFTZlB1ekdzMzZlWHFXbjJ6eHhvTFRBNElreHBXUEQ5QnZjSElGZGRwL2lQVDhueTkzSGx6bkkrCklyTDhlSDFGampTSFcyOGsrTmY3UnFRcWt2SWgwTW5BVXY3S1J3U09MbmV2bjBtNkUzZTlHYmZ2bHZTLzloTnAKS0ZoK2JVY2llTFVUY3gybUlDeFMvK0tsVy9vSWYzbHZoS0NUdGl6SGtPcWhSZ3Jkc2trNUZSeWp2bG9oT0NFTgpLd2ZpekM0TCtlZlRGQnUxTUZtVllFaG5KWUtJV1d5aUhIdjZOZHpJajJKbTMySjFSOFBGRFhPNW92ekxCYXMyCnhMc1RGRE13Mlo5TDE2WlBRYVAyd3ZuS1FOaXhQSnBWeFBjRWlrYmdRaGVwaWFmV09jZmlHeDl1UGx6R0R6enMKa0dVWDZDQkJBb0dCQVB2UVliSk9ZOExIeWRKWWkweXhnTURmWEp5Z1RQaDZXZnRROTl1UlJselluLy9LWXMraApZVnhPRStDbVd0TFMzQ1Fyc1N6Rk1jc2xXeFJiY01FQlE4Mm5HOE1xTDhLTmlVekMyNkhPSVJFaXg2b1JPbE9HCmRDZUVwWGQzSkE1Wk1TaklRQWNORXhnVzZZVTJCblVya0JhRXNpaDRrL2FLR2RjVmtZUWZPNUlKQW9HQkFQRVIKUW9aQ2tOSWFyNFpVakRJNVpoc2gvU0RjM0c2L21hQ0VDS1JFa09sZm5hbWtneTZOYmJnWEppREUvdVlLSDJ1RgpxbHJYMk9EckVaa3FvK0Y2UWg2blh3Wi9UWlZhL1VIZkdxd0d1c3k2Rzc5TlVHZGoySUFGcDVMNXZFcWg2K05RCkJ6ZFZJYTB3bFUyQzNxNmFFeDk2MXJ6a3ZJUEVLenVzRE9Lemg4dDVBb0dCQUlxSjRyWU9tcVFXOXRwYkRJaHQKUDhEZElqNnBrcTlCNFM5N0pHSVFVdjNSMEhVU0M3cmZ0b2pxQzlXVXNITTh2eERIV1BxZ292eDQyTnNpVTY1YgoyOG5SSGwwSllLMVE0VER5STVPcHJGZVpJdkJWK2hqcDZBMjExTE1kUVNFRHdTQUd5L01WSm1RaWR1ZHJDYko4Ci9SRG1nSDN6bUxRUzFwU1dzVEJYWHBiQkFvR0FRWkFRSjdPeTczR1NpMVl6U3ZXUmI0K3U2R0VwRW5YSnNuNDIKVzNiS2NxNHVreFRMR0w0ZU9STVNxNWJvUEdoRVkxblhHeDNaUGxLd1ZwZmlPbENsNnZCYVI4b1hyNmN2ZWRyVAp4aldPV0YvRmJDSDYzQ09ybmlYcmpXMmVhQzNobWRFS0pXSmg1bGh3UXNSMUM4ZWJxOVFjMHdMaXduTjN6cUxjClhrdTFnd0VDZ1lCNklsQzNFNXZ3anJBUXlUQ0pWUG1TU0Q3c2VrQWhnaTMyOE5GVUtPRyt0VmxkbzJ2QVloWFoKaU5lZU9XMVlRT1JqWU95MlJIeWJaVUk4WVZ5VHZ4bzZVdGtIbm1nak5CRWgwWGk2UDUvTEs5OTB3SWd1ZHRoYQp3SisyY0FMT3Y4OUlBQXQ2ZWRzQ3M5ODYrZVRxSE80aHJBQi96U01VWEtlYVJSY0s1UWxyL3c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= +kind: Secret +metadata: + creationTimestamp: null + name: config-bundle-secret + namespace: quay diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/config-qnap-example.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/config-qnap-example.yaml new file mode 100644 index 0000000..a843abe --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/config-qnap-example.yaml @@ -0,0 +1,31 @@ +EXTERNAL_TLS_TERMINATION: false +SERVER_HOSTNAME: registry.apps.home.ocplab.com +PREFERRED_URL_SCHEME: https +DISTRIBUTED_STORAGE_CONFIG: + # using Minio on QNAP NAS + radosGWStorage: + - RadosGWStorage + - access_key: XXXXX + secret_key: XXXX + bucket_name: quay + hostname: lab-nas.ocplab.com + is_secure: true + port: 9000 + storage_path: /datastorage/registry +DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [] +DISTRIBUTED_STORAGE_PREFERENCE: + - radosGWStorage +SSO_LOGIN_CONFIG: + CLIENT_ID: quay + CLIENT_SECRET: 723782ba-95d4-4d95-8b04-efebce0adf86 + OIDC_SERVER: https://sso-sso.apps.home.ocplab.com/auth/realms/openshift/ + LOGIN_SCOPES: + - openid + SERVICE_NAME: OpenShift +SUPER_USERS: + - admin + - quayadmin +FEATURE_DIRECT_LOGIN: true +FEATURE_USER_INITIALIZE: true +FEATURE_QUOTA_MANAGEMENT: true +FEATURE_PROXY_CACHE: true diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/create-qnap-sealed-secret.sh b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/create-qnap-sealed-secret.sh new file mode 100755 index 0000000..f9b2085 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/create-qnap-sealed-secret.sh @@ -0,0 +1,2 @@ +oc create secret generic --from-file config.yaml=./config-qnap-private.yaml config-bundle-secret --from-file=ssl.cert=fullchain.pem --from-file=ssl.key=key.pem -o yaml --dry-run=client -n quay > config-bundle-secret-qnap.yaml +kubeseal --format yaml --cert ~/.bitnami/publickey.pem < config-bundle-secret-qnap.yaml diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/generate-certs.sh b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/generate-certs.sh new file mode 100755 index 0000000..ef30d5f --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/generate/generate-certs.sh @@ -0,0 +1,7 @@ +# Using Route53 with DNS challenge, source AWS creds (not in git repo but just sets access and secret key as env variables) +. aws-creds +mkdir -p qnap-tls +acme.sh --force --issue --dns dns_aws --cert-file "./qnap-tls/cert.pem" --key-file "./qnap-tls/key.pem" --fullchain-file "./qnap-tls/fullchain.pem" --ca-file "./qnap-tls/ca.cer" -d registry.apps.home.ocplab.com + +# Convert CA to crt +openssl x509 -inform PEM -in ./qnap-tls/ca.cer -out ./qnap-tls/letsencrypt_ca.crt diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/init-quay-job.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/init-quay-job.yaml new file mode 100644 index 0000000..c145950 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/init-quay-job.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: quay-init +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: quay-init +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: admin +subjects: + - kind: ServiceAccount + name: quay-init +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: quay-init + annotations: + argocd.argoproj.io/sync-wave: "20" +spec: + template: + spec: + containers: + - image: registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:1.0 + envFrom: + - secretRef: + name: init-user-password + command: + - /bin/bash + - -c + - | + #!/usr/bin/env bash + + echo "Setup temporary OCP user to make ansible happy" + + echo "tempuser:x:$(id -u):$(id -g):,,,:${HOME}:/bin/bash" >> /etc/passwd + echo "tempuser:x:$(id -G | cut -d' ' -f 2)" >> /etc/group + id + + echo "Waiting for two minutes for quay to be ready" + + sleep 120 + + git clone https://github.com/gnunn-gitops/quay-init + + cd quay-init + + ansible-galaxy collection install -r collections/requirements.yaml + + ansible-playbook quay-init.yaml -e quay_init_password=$quay_init_password -e ansible_remote_tmp=/tmp + + echo "Waiting for deploy/registry-clair-app to be available" + until oc get deployment registry-clair-app + do + sleep 5; + done + oc scale deploy/registry-clair-app --replicas=1 + + echo "Waiting for deploy/registry-quay-app to be available" + until oc get deployment registry-quay-app + do + sleep 5; + done + oc set resources deploy/registry-quay-app -c=quay-app --requests=cpu=1,memory=1Gi --limits=cpu=2,memory=4Gi + oc scale deploy/registry-quay-app --replicas=1 + + echo "Waiting for deploy/registry-clair-postgres to be available" + until oc get deployment registry-clair-postgres + do + sleep 5; + done + oc set resources deploy/registry-clair-postgres -c=postgres --limits=memory=3Gi + + name: init-quay + dnsPolicy: ClusterFirst + restartPolicy: Never + terminationGracePeriodSeconds: 30 + serviceAccount: quay-init + serviceAccountName: quay-init diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/init-user-password-secret.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/init-user-password-secret.yaml new file mode 100644 index 0000000..3a31fef --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/init-user-password-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: init-user-password + namespace: quay + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + encryptedData: + quay_init_password: AgCFXt2+UWeWWgNO2EwPk10Vv07D8kXOYlVSPTi1AizSTJ35725eautJzhDSd1McS7A+VymUk6fdFDagx5oXJU7+Cr2V7n8sb+sQWQwiyaWuM4017PYHllCpMoU0Q5CF5yyZ11OyPPBi5Ucz391/TxgIZww9PGGXy2KolrL97fuvrVVgPdUdNw8SAG+6TlGTGiMuzg5VngLz8wKfNpQDdPum98DVRVvbzJHEp9Nu+rtglaCdLgsMcgTpWw59MKYsl7Slw7oZIxTZvRlu8m3DqGu+AqiFRGoLJpNhJ9aDMyH5QiQ+sf59VQILdTwTdPvC/wMAETKYqJ/PqEkTkYTsAdhS1AJDcMO2OoYGx7EheKNMRotjHSYor4DHedFqvVaA+X6ZjTU1so1Z5ToFW3tofnLXfrunuzUgU4Ld7pTl297Jyqy3J0kNF2vmsb0RExN8kbW+Rsk5rqHmYKm68lw28s+FI0Cejy29lk23j3V8m+WVY4ANtez1QTS0vU79+iauSVZx9Ab2hrD0IWLdU+18R+k1Mjd/ARBgxT/H6x4cGwhh32GF+46XPQpcNKrXeN0JsyDksllFHp6uXy6BYvDNxwm3eMVefOBdMkYr/z7pUqIYBtpQm9oyIEtr/j0f19CPmVX+glFsArVeCGizRrajtkLOb66x/OfoToZpwQzRalSwtHEHClLLXe8Y/HNm7vqx4golRYn3E3TiVOT0 + template: + metadata: + name: init-user-password + namespace: quay + type: Opaque diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/kustomization.yaml new file mode 100644 index 0000000..4b9af42 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +namespace: quay + +resources: +- github.com/redhat-cop/gitops-catalog/quay-operator/operator/overlays/stable-3.8 +- init-user-password-secret.yaml +- init-quay-job.yaml +- registry-config-bundle-secret.yaml +- registry.yaml +- registry-app-route.yaml diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry-app-route.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry-app-route.yaml new file mode 100644 index 0000000..8f8fa4d --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry-app-route.yaml @@ -0,0 +1,59 @@ +kind: Route +apiVersion: route.openshift.io/v1 +metadata: + name: registry-quay-app + labels: + app: quay + quay-component: quay-app + quay-operator/quayregistry: registry + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + host: registry.apps.home.ocplab.com + to: + kind: Service + name: registry-quay-app + weight: 100 + port: + targetPort: https + tls: + termination: passthrough + wildcardPolicy: None +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: registry-quay-builder + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + host: registry-builder.apps.home.ocplab.com + port: + targetPort: grpc + tls: + insecureEdgeTerminationPolicy: Redirect + termination: reencrypt + to: + kind: Service + name: registry-quay-app + weight: 100 + wildcardPolicy: None +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: registry-quay-config-editor + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + host: registry-config-editor.apps.home.ocplab.com + port: + targetPort: http + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: registry-quay-config-editor + weight: 100 + wildcardPolicy: None diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry-config-bundle-secret.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry-config-bundle-secret.yaml new file mode 100644 index 0000000..c7b07a5 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry-config-bundle-secret.yaml @@ -0,0 +1,14 @@ +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + name: config-bundle-secret + namespace: quay +spec: + encryptedData: + config.yaml: AgCIl9LCyxEuz9IxO53ydUGhQIbf3c/wSGtS4dAMPeAKxCYvc8hPYa96kz/ogsSAAPtNqSzR4PzMFhODTfuNt7fkBUcsmMRLAPCghVySBYQZOaYmpkzr42i1B0S8KSHFkl3KDltu7QZWfiBz2cT3t5ghLU4AXNkpDAqUt2yCuYyeTxF14ND53kwWbu50n6GALUsWPKq6KHvlC1iRNk2cFMKMYVBjVYPNFrvnCLnJcCxHULAMy+IqIzHW76MWxeHGpQuWuaPK4g7YBOtjB3gs2KnqE2IsMOqTIgnp575CdyW443WNx8PbdgcaENfC+LTyjkhBgO1F9MXSJaR8Sd/Ou3Bj/u73ki/9Gi2SEJSIra+L+RMnXT/PG7orcFL0pIWONDomlfD2cG2Ky6aIhPDoJOWxUiUpGP7RHQ6sw0X/BlopOCu4c/7cb8RPaLzESG4E7w4k11OjuqsiAm92ZIvPegjIbSD4je2sVqMF9eEthwzydutgQznV3zGNkVd/L4cdI9lBo6yVKHF/imgiA7nwtaMMZN848RRMlsoiGhE8VCDYswBvMvOyoiBG1E7naijrGoeaP3GX9LIpzU6mHSLQ0aM/Pyi162wyNYo4ZLLXQ+EA+V3d4ku1AZ/ZffLXLo0nZTcyUIt0odDp3JhsBPXKzEoF843tfK7sONxxiV/xfBnTfJgfnEhxZTXq1L14VFS6NkQZR/Y8xTdUia6fFQ6nS0dkzZ5sxX6dzBeeCVgfD4WupiJ53PTAl8TqBVgi4PIFdCdCDuvt5PP1Uanr03KQG8+1fjtIJJOkOME9XgFL9ohMrhYkNqF/I8tR+LF69H7ynH+NfrmvrzMKQiDpFjY1E+Dv0hEQDe/2mjAen/Vj9dOaxYa21PU7i+Gt6/0zhveLu4nkfevUj2zFeuDXqZ1KothrPzh+xgRhSB8naf9041YYA8NPUaRFo2+DUH/YZXMfXnE36N5A1IEp3AESPrg99A+qMaQtO+oY4PYdBeWqbKYgihAcdHmlv3ZWIMHksGG352uOLSwF70VV/6p0QecM5bbP2WF6b5OWIIGZ9jarCKDJPaHh3Q/QevNwgdZIxvmVr9/FY/zhYQVOD6GXgI28E4M91nd2Kt7fZb3twscs+XgwZo2whO6I7AS3LZ0dKQIYFNSTd18s0j2z2NrLZzvnp4W36vaxvUVpGnyRsuMplwsGILlz+F3yN0qoxyZZJXl4Nhh2BbEkVacxVUrO6uMHL9BVZtW34D1P/KQJ/1dHm8hM5VZiyQHy9paVEgb7aPJ8Fwcq71mgjsSfqfNMDxBCrCq6i+mj26JKiS2bOno8eka42pNBPjEksRAAMJYI+UyO/k0XiN7Z+xXhkikgc+f++rV3HACnorisC759PVmUxM1Fu5/tdPKAp7WndHJ3/EHHen9ot7vG6VQERdnRWFYxGDxwH4qwIOJaM1Uwv/jBvJn3PJWIpF2d30VarxKoNat1g0RGKxq8nyKkpzQWRNICEC5v5Szd0n6s4FdRsQ5oDU9V4FwmrPFXUYiPjGgvvVTfDG7qLpfskajcjnbnYMsQIeBIz3dGo8z+DX/H4S676G50+alXhfEWgVJZrJSpUaMx2IFJno+xrvNYBER0m2orfwE3OBtmAXT3ac+EaAlvpi/fZAasp58gFVjCb4gNSaGbhZFKY62Oduyitfn4G6fTUUOhC9VyYUC6RJm5eJ9uPETqWTbebbG9Pe0PKMBJiAbcZ4PXEtNL8hey/iLo7SM3EhPPW9B0DtiqrX7rCEh1KwQZjbjIY4KuanNj5g5jkd20vvfVbPm9ZqITGpQM3BNH5ilh0tJ0YoigdBxJkt1vZmhWeR3ISLMokPK4A/g= + ssl.cert: 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 + ssl.key: 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 + template: + metadata: + name: config-bundle-secret + namespace: quay diff --git a/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry.yaml b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry.yaml new file mode 100644 index 0000000..d81f5a5 --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/quay-registry-operator/registry.yaml @@ -0,0 +1,27 @@ +apiVersion: quay.redhat.com/v1 +kind: QuayRegistry +metadata: + name: registry + annotations: + argocd.argoproj.io/sync-wave: "10" +spec: + components: + - managed: false + kind: tls + - managed: false + kind: horizontalpodautoscaler + - kind: route + managed: false + - kind: postgres + managed: true + - kind: clair + managed: true + - kind: redis + managed: true + - kind: mirror + managed: true + - kind: monitoring + managed: false + - kind: objectstorage + managed: false + configBundleSecret: config-bundle-secret diff --git a/cluster-config/clusters/overlays/local.hub/components/rhtas-operator/kustomization.yaml b/cluster-config/clusters/overlays/local.hub/components/rhtas-operator/kustomization.yaml new file mode 100644 index 0000000..8860d2c --- /dev/null +++ b/cluster-config/clusters/overlays/local.hub/components/rhtas-operator/kustomization.yaml @@ -0,0 +1,14 @@ +resources: +- ../../../../../components/rhtas-operator/operator/base +- ../../../../../components/rhtas-operator/instance/base + +patches: +- patch: | + - op: replace + path: /spec/fulcio/config/OIDCIssuers/0/Issuer + value: https://sso.ocplab.com/realms/ocplab + - op: replace + path: /spec/fulcio/config/OIDCIssuers/0/IssuerURL + value: https://sso.ocplab.com/realms/ocplab + target: + kind: Securesign diff --git a/cluster-config/clusters/overlays/rhdp/components/openshift-monitoring/base/cluster-monitoring-config-cm.yaml b/cluster-config/clusters/overlays/rhdp/components/openshift-monitoring/base/cluster-monitoring-config-cm.yaml new file mode 100644 index 0000000..0d76888 --- /dev/null +++ b/cluster-config/clusters/overlays/rhdp/components/openshift-monitoring/base/cluster-monitoring-config-cm.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cluster-monitoring-config + namespace: openshift-monitoring +data: + config.yaml: | + enableUserWorkload: true diff --git a/cluster-config/clusters/overlays/rhdp/components/openshift-monitoring/base/kustomization.yaml b/cluster-config/clusters/overlays/rhdp/components/openshift-monitoring/base/kustomization.yaml new file mode 100644 index 0000000..8db0fd3 --- /dev/null +++ b/cluster-config/clusters/overlays/rhdp/components/openshift-monitoring/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- cluster-monitoring-config-cm.yaml diff --git a/cluster-config/components/3scale-operator/base/apimanager.yaml b/cluster-config/components/3scale-operator/base/apimanager.yaml new file mode 100644 index 0000000..9f91862 --- /dev/null +++ b/cluster-config/components/3scale-operator/base/apimanager.yaml @@ -0,0 +1,38 @@ +apiVersion: apps.3scale.net/v1alpha1 +kind: APIManager +metadata: + name: apimanager + namespace: 3scale +spec: + resourceRequirementsEnabled: true + wildcardDomain: 3scale.apps.home.ocplab.com + system: + database: + postgresql: + persistentVolumeClaim: + storageClassName: iscsi + redisPersistentVolumeClaim: + storageClassName: iscsi + fileStorage: + persistentVolumeClaim: + storageClassName: managed-nfs-storage + redisResources: + requests: + cpu: 150m + memory: 256Mi + limits: + cpu: 500m + memory: 4Gi + backend: + redisPersistentVolumeClaim: + storageClassName: iscsi + redisResources: + limits: + cpu: 500m + memory: 4Gi + requests: + cpu: 150m + memory: 256Mi + fileStorage: + persistentVolumeClaim: + storageClassName: managed-nfs-storage diff --git a/cluster-config/components/acs-config/base/declarative-config.yaml b/cluster-config/components/acs-config/base/declarative-config.yaml new file mode 100644 index 0000000..2c67039 --- /dev/null +++ b/cluster-config/components/acs-config/base/declarative-config.yaml @@ -0,0 +1,125 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: declarative-configurations + namespace: stackrox +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: declarative-configurations + creationPolicy: Owner + template: + data: + keycloak-auth.yaml: | + name: keycloak + minimumRole: None + uiEndpoint: central-stackrox.${SUB_DOMAIN}:443 + oidc: + issuer: https://keycloak.${SUB_DOMAIN}/realms/openshift + mode: auto + clientID: acs + clientSecret: {{ .keycloak_client_secret }} + disableOfflineAccessScope: true + groups: + - key: email + value: admin@ocplab.com + role: Admin + - key: email + value: clusteradmin@workshop-noreply.com + role: Admin + - key: email + value: gnunn+user1@redhat.com + role: Product Catalog Admins + openshift-auth.yaml: | + name: openshift + uiEndpoint: central-stackrox.${SUB_DOMAIN}:443 + openshift: + enable: true + minimumRole: None + groups: + - key: name + value: admin + role: Admin + - key: groups + value: product-catalog-admins + role: Product Catalog Admins + product-catalog-access-scope.yaml: | + name: product-catalog-admins + description: Access rights for users that can manage Product Catalog namespaces + rules: + includedNamespaces: + - clusterName: home + namespaceName: product-catalog-dev + - clusterName: home + namespaceName: product-catalog-test + - clusterName: home + namespaceName: product-catalog-monitor + - clusterName: home + namespaceName: product-catalog-prod + - clusterName: home + namespaceName: product-catalog-cicd + - clusterName: home + namespaceName: product-catalog-gitops + namespace-admin-permission-set.yaml: | + name: Namespace Administrator + description: A user that is an administrator of one or namespaces across various clusters + resources: + - resource: Access + access: NO_ACCESS + - resource: Administration + access: NO_ACCESS + - resource: Alert + access: READ_ACCESS + - resource: CVE + access: READ_ACCESS + - resource: Cluster + access: READ_ACCESS + - resource: Compliance + access: READ_ACCESS + - resource: Deployment + access: READ_ACCESS + - resource: DeploymentExtension + access: READ_ACCESS + - resource: Detection + access: READ_ACCESS + - resource: Image + access: READ_ACCESS + - resource: Integration + access: NO_ACCESS + - resource: K8sRole + access: READ_ACCESS + - resource: K8sRoleBinding + access: READ_ACCESS + - resource: K8sSubject + access: READ_ACCESS + - resource: Namespace + access: READ_ACCESS + - resource: NetworkGraph + access: READ_ACCESS + - resource: NetworkPolicy + access: READ_ACCESS + - resource: Node + access: READ_ACCESS + - resource: Secret + access: READ_ACCESS + - resource: ServiceAccount + access: READ_ACCESS + - resource: WatchedImage + access: READ_WRITE_ACCESS + - resource: VulnerabilityManagementApprovals + access: READ_ACCESS + - resource: VulnerabilityManagementRequests + access: READ_WRITE_ACCESS + product-catalog-roles.yaml: | + name: Product Catalog Admins + description: Administrators of product catalog namespaces + permissionSet: Namespace Administrator + accessScope: product-catalog-admins + globalAccess: NO_ACCESS + data: + - secretKey: keycloak_client_secret + remoteRef: + key: ACS_KEYCLOAK_CLIENT_SECRET diff --git a/cluster-config/components/acs-config/base/kustomization.yaml b/cluster-config/components/acs-config/base/kustomization.yaml new file mode 100644 index 0000000..26cd66d --- /dev/null +++ b/cluster-config/components/acs-config/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- declarative-config.yaml diff --git a/cluster-config/components/acs-operator/overlays/aggregate/admission-control-tls-push-secret.yaml b/cluster-config/components/acs-operator/overlays/aggregate/admission-control-tls-push-secret.yaml new file mode 100644 index 0000000..76834cf --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/aggregate/admission-control-tls-push-secret.yaml @@ -0,0 +1,26 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: admission-tls + namespace: stackrox +spec: + refreshInterval: 10s + secretStoreRefs: + - name: doppler-push-secret + kind: ClusterSecretStore + selector: + secret: + name: admission-control-tls + data: + - match: + secretKey: ca.pem + remoteRef: + remoteKey: ACS_ADMISSION_CONTROL_TLS_CA + - match: + secretKey: admission-control-cert.pem + remoteRef: + remoteKey: ACS_ADMISSION_CONTROL_TLS_CERT + - match: + secretKey: admission-control-key.pem + remoteRef: + remoteKey: ACS_ADMISSION_CONTROL_TLS_KEY diff --git a/cluster-config/components/acs-operator/overlays/aggregate/collector-tls-push-secret.yaml b/cluster-config/components/acs-operator/overlays/aggregate/collector-tls-push-secret.yaml new file mode 100644 index 0000000..7a49e74 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/aggregate/collector-tls-push-secret.yaml @@ -0,0 +1,26 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: collector-tls + namespace: stackrox +spec: + refreshInterval: 10s + secretStoreRefs: + - name: doppler-push-secret + kind: ClusterSecretStore + selector: + secret: + name: collector-tls + data: + - match: + secretKey: ca.pem + remoteRef: + remoteKey: ACS_COLLECTOR_TLS_CA + - match: + secretKey: collector-cert.pem + remoteRef: + remoteKey: ACS_COLLECTOR_TLS_CERT + - match: + secretKey: collector-key.pem + remoteRef: + remoteKey: ACS_COLLECTOR_TLS_KEY diff --git a/cluster-config/components/acs-operator/overlays/aggregate/kustomization.yaml b/cluster-config/components/acs-operator/overlays/aggregate/kustomization.yaml new file mode 100644 index 0000000..cf2c2d8 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/aggregate/kustomization.yaml @@ -0,0 +1,31 @@ +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +resources: + - github.com/redhat-cop/gitops-catalog/advanced-cluster-security-operator/aggregate/default + - admission-control-tls-push-secret.yaml + - collector-tls-push-secret.yaml + - sensor-tls-push-secret.yaml + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: 'rhacs-4.7' + target: + kind: Subscription + name: rhacs-operator + - patch: |- + - op: replace + path: /spec/perNode/collector/collection + value: EBPF + target: + kind: SecuredCluster + - patch: |- + - op: add + path: /spec/central/declarativeConfiguration + value: + secrets: + - name: declarative-configurations + target: + kind: Central diff --git a/cluster-config/components/acs-operator/overlays/aggregate/sensor-tls-push-secret.yaml b/cluster-config/components/acs-operator/overlays/aggregate/sensor-tls-push-secret.yaml new file mode 100644 index 0000000..119a5b2 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/aggregate/sensor-tls-push-secret.yaml @@ -0,0 +1,26 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: sensor-tls + namespace: stackrox +spec: + refreshInterval: 10s + secretStoreRefs: + - name: doppler-push-secret + kind: ClusterSecretStore + selector: + secret: + name: sensor-tls + data: + - match: + secretKey: ca.pem + remoteRef: + remoteKey: ACS_SENSOR_TLS_CA + - match: + secretKey: sensor-cert.pem + remoteRef: + remoteKey: ACS_SENSOR_TLS_CERT + - match: + secretKey: sensor-key.pem + remoteRef: + remoteKey: ACS_SENSOR_TLS_KEY diff --git a/cluster-config/components/acs-operator/overlays/secured-cluster/acs-admission-control-tls-secret.yaml b/cluster-config/components/acs-operator/overlays/secured-cluster/acs-admission-control-tls-secret.yaml new file mode 100644 index 0000000..e351a8e --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/secured-cluster/acs-admission-control-tls-secret.yaml @@ -0,0 +1,25 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: admission-control-tls + namespace: stackrox-secured-cluster-service +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: admission-control-tls + creationPolicy: Owner + data: + - secretKey: ca.pem + remoteRef: + key: ACS_ADMISSION_CONTROL_TLS_CA + - secretKey: admission-control-cert.pem + remoteRef: + key: ACS_ADMISSION_CONTROL_TLS_CERT + - secretKey: admission-control-key.pem + remoteRef: + key: ACS_ADMISSION_CONTROL_TLS_KEY diff --git a/cluster-config/components/acs-operator/overlays/secured-cluster/acs-collector-tls-secret.yaml b/cluster-config/components/acs-operator/overlays/secured-cluster/acs-collector-tls-secret.yaml new file mode 100644 index 0000000..8796b56 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/secured-cluster/acs-collector-tls-secret.yaml @@ -0,0 +1,25 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: collector-tls + namespace: stackrox-secured-cluster-service +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: collector-tls + creationPolicy: Owner + data: + - secretKey: ca.pem + remoteRef: + key: ACS_COLLECTOR_TLS_CA + - secretKey: collector-cert.pem + remoteRef: + key: ACS_COLLECTOR_TLS_CERT + - secretKey: collector-key.pem + remoteRef: + key: ACS_COLLECTOR_TLS_KEY diff --git a/cluster-config/components/acs-operator/overlays/secured-cluster/acs-sensor-tls-secret.yaml b/cluster-config/components/acs-operator/overlays/secured-cluster/acs-sensor-tls-secret.yaml new file mode 100644 index 0000000..cff9e1f --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/secured-cluster/acs-sensor-tls-secret.yaml @@ -0,0 +1,25 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: sensor-tls + namespace: stackrox-secured-cluster-service +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: sensor-tls + creationPolicy: Owner + data: + - secretKey: ca.pem + remoteRef: + key: ACS_SENSOR_TLS_CA + - secretKey: sensor-cert.pem + remoteRef: + key: ACS_SENSOR_TLS_CERT + - secretKey: sensor-key.pem + remoteRef: + key: ACS_SENSOR_TLS_KEY diff --git a/cluster-config/components/acs-operator/overlays/secured-cluster/kustomization.yaml b/cluster-config/components/acs-operator/overlays/secured-cluster/kustomization.yaml new file mode 100644 index 0000000..df58d33 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/secured-cluster/kustomization.yaml @@ -0,0 +1,19 @@ +# commonAnnotations: +# argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +resources: +- github.com/redhat-cop/gitops-catalog/advanced-cluster-security-operator/operator/overlays/latest +- namespace.yaml +- acs-admission-control-tls-secret.yaml +- acs-sensor-tls-secret.yaml +- acs-collector-tls-secret.yaml +- secured-cluster.yaml + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: 'rhacs-4.7' + target: + kind: Subscription + name: rhacs-operator diff --git a/cluster-config/components/acs-operator/overlays/secured-cluster/namespace.yaml b/cluster-config/components/acs-operator/overlays/secured-cluster/namespace.yaml new file mode 100644 index 0000000..7037f09 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/secured-cluster/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: stackrox-secured-cluster-service diff --git a/cluster-config/components/acs-operator/overlays/secured-cluster/secured-cluster.yaml b/cluster-config/components/acs-operator/overlays/secured-cluster/secured-cluster.yaml new file mode 100644 index 0000000..7fa2321 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/secured-cluster/secured-cluster.yaml @@ -0,0 +1,18 @@ +kind: SecuredCluster +apiVersion: platform.stackrox.io/v1alpha1 +metadata: + annotations: + argocd.argoproj.io/sync-wave: "5" + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: stackrox-secured-cluster-services + namespace: stackrox-secured-cluster-service +spec: + clusterName: ${CLUSTER_NAME} + centralEndpoint: central-stackrox.apps.hub.ocplab.com:443 + admissionControl: + contactImageScanners: ScanIfMissing + listenOnCreates: true + listenOnUpdates: true + timeoutSeconds: 6 + scannerV4: + scannerComponent: Default diff --git a/cluster-config/components/acs-operator/overlays/sso/create-sso-auth-provider-job.yaml b/cluster-config/components/acs-operator/overlays/sso/create-sso-auth-provider-job.yaml new file mode 100644 index 0000000..6ebfb2f --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/sso/create-sso-auth-provider-job.yaml @@ -0,0 +1,79 @@ +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/sync-wave: "10" + name: create-sso-auth-provider + namespace: stackrox +spec: + template: + spec: + containers: + - image: image-registry.openshift-image-registry.svc:5000/openshift/cli:latest + env: + - name: CLIENT_SECRET + valueFrom: + secretKeyRef: + name: sso-secret + key: client-secret + - name: PASSWORD + valueFrom: + secretKeyRef: + name: central-htpasswd + key: password + - name: ISSUER + value: https://sso-sso.apps.home.ocplab.com/auth/realms/openshift + - name: DEFAULT_ROLE + value: Admin + command: + - /bin/bash + - -c + - | + #!/usr/bin/env bash + + # Wait for central to be ready + attempt_counter=0 + max_attempts=20 + echo "Waiting for central to be available..." + until $(curl -k --output /dev/null --silent --head --fail https://central); do + if [ ${attempt_counter} -eq ${max_attempts} ];then + echo "Max attempts reached" + exit 1 + fi + printf '.' + attempt_counter=$(($attempt_counter+1)) + echo "Made attempt $attempt_counter, waiting..." + sleep 5 + done + + echo "Configuring SSO Provider" + + echo "Test if SSO Provider already exists" + + response=$(curl -k -u "admin:$PASSWORD" https://central/v1/authProviders?name=OpenShift | python3 -c "import sys, json; print(json.load(sys.stdin)['authProviders'], end = '')") + + if [[ "$response" != "[]" ]] ; then + echo "OpenShift Provider already exists, exiting" + exit 0 + fi + + export DATA='{"name":"OpenShift","type":"oidc","uiEndpoint":"central-stackrox.apps.home.ocplab.com","enabled":true,"config":{"client_id":"stackrox","client_secret":"'${CLIENT_SECRET}'","issuer":"'$ISSUER'","mode":"post"},"validated":true,"extraUiEndpoints":[],"active":true}' + + echo "Posting data: ${DATA}" + + authid=$(curl -k -X POST -u "admin:$PASSWORD" -H "Content-Type: application/json" --data $DATA https://central/v1/authProviders | python3 -c "import sys, json; print(json.load(sys.stdin)['id'], end = '')") + + echo "Authentication Provider created with id ${authid}" + echo "Updating minimum role to Admin" + + export DATA='{"previous_groups":[],"required_groups":[{"props":{"authProviderId":"'${authid}'"},"roleName":"'${DEFAULT_ROLE}'"}]}' + + curl -k -X POST -u "admin:$PASSWORD" -H "Content-Type: application/json" --data $DATA https://central/v1/groupsbatch + + imagePullPolicy: Always + name: create-sso-auth-provider + dnsPolicy: ClusterFirst + restartPolicy: Never + serviceAccount: create-cluster-init + serviceAccountName: create-cluster-init + terminationGracePeriodSeconds: 30 diff --git a/cluster-config/components/acs-operator/overlays/sso/kustomization.yaml b/cluster-config/components/acs-operator/overlays/sso/kustomization.yaml new file mode 100644 index 0000000..624e72b --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/sso/kustomization.yaml @@ -0,0 +1,18 @@ +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +resources: + - github.com/redhat-cop/gitops-catalog/advanced-cluster-security-operator/operator/overlays/latest + - github.com/redhat-cop/gitops-catalog/advanced-cluster-security-operator/instance/overlays/internal-registry-integration + - sso-sealed-secret.yaml + - create-sso-auth-provider-job.yaml + # Use Andrew's Pipeline to create Stackrox API Tokens in tenant namespaces + - github.com/pittar-gitops/gitops-mono-repo-admins/03-cluster-services/08-advanced-cluster-security/pipelines-and-secrets + +patchesJson6902: + - path: patch-resources.yaml + target: + group: platform.stackrox.io + kind: Central + name: central + version: v1alpha1 diff --git a/cluster-config/components/acs-operator/overlays/sso/patch-resources.yaml b/cluster-config/components/acs-operator/overlays/sso/patch-resources.yaml new file mode 100644 index 0000000..3044057 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/sso/patch-resources.yaml @@ -0,0 +1,22 @@ +- op: add + path: /spec/central/resources + value: + limits: + memory: 2Gi + requests: + cpu: 500m + memory: 512Mi +- op: add + path: /spec/scanner/analyzer/resources + value: + limits: + memory: 1Gi + requests: + cpu: 250m + memory: 500Mi +- op: replace + path: /spec/scanner/analyzer/scaling/autoScaling + value: Disabled +- op: replace + path: /spec/scanner/analyzer/scaling/replicas + value: 2 diff --git a/cluster-config/components/acs-operator/overlays/sso/sso-sealed-secret.yaml b/cluster-config/components/acs-operator/overlays/sso/sso-sealed-secret.yaml new file mode 100644 index 0000000..9e3e563 --- /dev/null +++ b/cluster-config/components/acs-operator/overlays/sso/sso-sealed-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: sso-secret + namespace: stackrox +spec: + encryptedData: + client-secret: AgCk7m6UEoCoLvvLbUW+lXnYxaZ9Hm520Xg9/h9KMifm9mqFnzfxdlPksgZ0SIyw446ThrpAd/x39K1Azm5tMgQwIn+DaTOaDS3NVrwQWnaTBFph5AJ8DbcAMKFfSZAddCCizPlfkB3kv7zL8EIbj9d59Qbn3/0mu4hgqN0I2kOptQwFXt+kYYChrJ13LwDVJ5/wxPCa1VKUQ/osSX9wrddRBn/UQLPpXtH8loePfjn+9/oMMq49S4oiN9AjNUzuLLQHmg0OmeRtH34lGAkFgWHjNboOUDsmDCb78olGKTDIzNJ/Xz6iFmszZm1bhj7IG/VtcGoxroC/eddp1chGq4M8pMYEQkON6vp1bzP6LY3x6PxLjFg0Yl1EPSMZXyONNWJ9pl4drPsJqnw0QqLQG172ucbpGy2CwiaZ4ZwPtp/JcPJCDVW2nwwJNyNodfS8DgUbTF+cHm3/W0Z5BWi5CQvXBMRF3a9LyIuRoFW9w5XNnqKQP0lP/8NKW1K5LmgpVuJSGNg6JEQyRSDnK7WAnfDReDTTTEoivjFFQ7uUJFP/RDYWiXvSE3hNYse331QO5DCATmyDPm36txFaKtfVy/TdVhU7gV07FHPQju7IqfoI9pkc0pQtFUUYB9nFamuHsvkO4brnAjIYuCl7SJeM8xK37xLO4KgbKm/ldqxb80eUScBH963Lk9+H4zgyJ5Wq04dDdnxWrBedXjY00UBbmJ4CVDoGL/24HHbi118ZFTa3N9AJDss= + template: + metadata: + name: sso-secret + namespace: stackrox + type: Opaque diff --git a/cluster-config/components/acs-tokens/base/README.md b/cluster-config/components/acs-tokens/base/README.md new file mode 100644 index 0000000..710a592 --- /dev/null +++ b/cluster-config/components/acs-tokens/base/README.md @@ -0,0 +1,7 @@ +## Not being used at the moment, use at your own risk :) + +Uses a post-sync hook to generate ACS tokens for various namespaces to consume. Useful when there is a need to integrate with ACS for image scanning, etc. + +Namespaces can be passed in a comma-separated list via environment variables. + +based on Andrew Pitt's tekton task here: https://github.com/pittar-gitops/gitops-mono-repo-admins/tree/main/03-cluster-services/08-advanced-cluster-security/pipelines-and-secrets diff --git a/cluster-config/components/acs-tokens/base/kustomization.yaml b/cluster-config/components/acs-tokens/base/kustomization.yaml new file mode 100644 index 0000000..b2459b9 --- /dev/null +++ b/cluster-config/components/acs-tokens/base/kustomization.yaml @@ -0,0 +1,6 @@ +namespace: stackrox + +resources: + - postsync-create-roxsecrets-sa-rbac.yaml + - postsync-create-roxsecrets-job.yaml + - postsync-roxsecret-namespaces.yaml diff --git a/cluster-config/components/acs-tokens/base/postsync-create-roxsecrets-job.yaml b/cluster-config/components/acs-tokens/base/postsync-create-roxsecrets-job.yaml new file mode 100644 index 0000000..099a9e6 --- /dev/null +++ b/cluster-config/components/acs-tokens/base/postsync-create-roxsecrets-job.yaml @@ -0,0 +1,85 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: postsync-create-roxsecrets-job + namespace: stackrox + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + template: + spec: + containers: + - image: quay.io/gnunn/tools:4.10-1 + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + key: password + name: central-htpasswd + envFrom: + - configMapRef: + name: roxsecret-namespaces + command: + - /bin/bash + - -c + - | + # Wait for central to be ready + attempt_counter=0 + max_attempts=20 + echo "Waiting for central to be available..." + until $(curl -k --output /dev/null --silent --head --fail https://$CENTRAL_URL); do + if [ ${attempt_counter} -eq ${max_attempts} ];then + echo "Max attempts reached" + exit 1 + fi + printf '.' + attempt_counter=$(($attempt_counter+1)) + echo "Made attempt $attempt_counter, waiting..." + sleep 10 + done + + API_ENDPOINT="/v1/apitokens/generate" + CENTRAL_URL_API="https://$CENTRAL_URL$API_ENDPOINT" + echo "Central API endpoint: $CENTRAL_URL_API" + echo "Creating secrets in namespaces $NAMESPACES" + + for NAMESPACE in ${NAMESPACES//,/ } + do + echo "Creating secret for $NAMESPACE" + if [[ `oc get namespace $NAMESPACE 2>/dev/null` ]] ; + then + echo "Namespace '$NAMESPACE' exists, checking secret..." + else + echo "Namespace '$NAMESPACE' doesn't exist, skipping" + continue + fi + + # If secret already exists, don't regenerate. + if [[ -n `oc get secret roxsecrets -n $NAMESPACE 2>/dev/null` ]] ; + then + echo "Stackrox token secret already exists in $NAMESPACE" + continue + fi + PAYLOAD="{\"name\": \"$NAMESPACE\", \"role\": \"Continuous Integration\"}" + echo "$PAYLOAD" + echo "Generate new token." + RESPONSE=$(curl -k \ + -X POST -u "admin:$PASSWORD" \ + -H "Content-Type: application/json" \ + --data "$PAYLOAD" \ + $CENTRAL_URL_API) + TOKEN=$(jq -r '.token' <<< "$RESPONSE") + + # Create secret in target namespace + oc create secret generic roxsecrets \ + --from-literal=rox_central_endpoint=$CENTRAL_URL:443 \ + --from-literal=rox_api_token=$TOKEN \ + -n $NAMESPACE + done + name: create-secrets + dnsPolicy: ClusterFirst + restartPolicy: Never + terminationGracePeriodSeconds: 30 + serviceAccount: postsync-create-roxsecrets + serviceAccountName: postsync-create-roxsecrets diff --git a/cluster-config/components/acs-tokens/base/postsync-create-roxsecrets-sa-rbac.yaml b/cluster-config/components/acs-tokens/base/postsync-create-roxsecrets-sa-rbac.yaml new file mode 100644 index 0000000..007f889 --- /dev/null +++ b/cluster-config/components/acs-tokens/base/postsync-create-roxsecrets-sa-rbac.yaml @@ -0,0 +1,40 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: postsync-create-roxsecrets + namespace: stackrox +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + argocd.argoproj.io/sync-wave: "1" + name: postsync-create-roxsecrets + namespace: stackrox +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: postsync-create-roxsecrets +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: postsync-create-roxsecrets +subjects: + - kind: ServiceAccount + name: postsync-create-roxsecrets + namespace: stackrox diff --git a/cluster-config/components/acs-tokens/base/postsync-roxsecret-namespaces.yaml b/cluster-config/components/acs-tokens/base/postsync-roxsecret-namespaces.yaml new file mode 100644 index 0000000..f8cb74e --- /dev/null +++ b/cluster-config/components/acs-tokens/base/postsync-roxsecret-namespaces.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: roxsecret-namespaces + namespace: stackrox +data: + NAMESPACES: product-catalog-cicd,demo-cicd + CENTRAL_URL: central-stackrox.apps.hub.ocplab.com diff --git a/cluster-config/components/alertmanager/base/README.md b/cluster-config/components/alertmanager/base/README.md new file mode 100644 index 0000000..34b4a1b --- /dev/null +++ b/cluster-config/components/alertmanager/base/README.md @@ -0,0 +1 @@ +See Jonas Janz's repo for examples of alertmanager configuration and slack template [here](https://github.com/PixelJonas/cluster-gitops/tree/master/manifests/argocd/apps/alertmanager/base/apps/examples). diff --git a/cluster-config/components/alertmanager/base/alertmanager-main-secret.yaml b/cluster-config/components/alertmanager/base/alertmanager-main-secret.yaml new file mode 100644 index 0000000..9fbfe38 --- /dev/null +++ b/cluster-config/components/alertmanager/base/alertmanager-main-secret.yaml @@ -0,0 +1,18 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: alertmanager-main + namespace: openshift-monitoring +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: alertmanager-main + data: + - secretKey: alertmanager.yaml + remoteRef: + key: ALERTMANAGER + - secretKey: slacktemplate.tmpl + remoteRef: + key: ALERTMANAGER_SLACK_TEMPLATE diff --git a/cluster-config/components/alertmanager/base/kustomization.yaml b/cluster-config/components/alertmanager/base/kustomization.yaml new file mode 100644 index 0000000..1ea71ad --- /dev/null +++ b/cluster-config/components/alertmanager/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- alertmanager-main-secret.yaml diff --git a/cluster-config/components/amq-streams-v1/base/README.md b/cluster-config/components/amq-streams-v1/base/README.md new file mode 100644 index 0000000..a3ac2d6 --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/README.md @@ -0,0 +1 @@ +Experimenting with OLM v1 diff --git a/cluster-config/components/amq-streams-v1/base/clusterextension.yaml b/cluster-config/components/amq-streams-v1/base/clusterextension.yaml new file mode 100644 index 0000000..6c41fd0 --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/clusterextension.yaml @@ -0,0 +1,15 @@ +apiVersion: olm.operatorframework.io/v1 +kind: ClusterExtension +metadata: + name: amq-streams +spec: + namespace: amq-streams-operator + serviceAccount: + name: amq-streams-installer + source: + sourceType: Catalog + catalog: + packageName: amq-streams + channels: + - amq-streams-2.9.x + upgradeConstraintPolicy: CatalogProvided diff --git a/cluster-config/components/amq-streams-v1/base/clusterrole.yaml b/cluster-config/components/amq-streams-v1/base/clusterrole.yaml new file mode 100644 index 0000000..51b17ff --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/clusterrole.yaml @@ -0,0 +1,398 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: amq-streams-installer-clusterrole +rules: + # ClusterRoles and ClusterRoleBindings for the controllers of the extension + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + verbs: + - "*" + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + verbs: + - "*" + - apiGroups: + - olm.operatorframework.io + resources: + - clusterextensions/finalizers + verbs: + - update + # Scoped to the name of the ClusterExtension + resourceNames: + - amq-streams # the value from from the extension's custom resource (CR) + # Deployments specified in install.spec.deployments + - apiGroups: + - apps + resources: + - deployments + verbs: + - create + - list + - watch + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - update + - patch + - delete + # scoped to the extension controller deployment name + resourceNames: + - amq-streams-cluster-operator + - amq-streams-cluster-operator-v2.9.0-0 + # Service accounts in the CSV + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - list + - watch + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - update + - patch + - delete + # scoped to the extension controller's deployment service account + resourceNames: + - strimzi-cluster-operator + # configmaps + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - update + - patch + - delete + # scoped to the configmap name + resourceNames: + - strimzi-cluster-operator + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - create + - list + - watch + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + - patch + - delete + resourceNames: + - kafkas.kafka.strimzi.io + - kafkanodepools.kafka.strimzi.io + - kafkaconnects.kafka.strimzi.io + - kafkamirrormakers.kafka.strimzi.io + - kafkabridges.kafka.strimzi.io + - kafkatopics.kafka.strimzi.io + - kafkausers.kafka.strimzi.io + - kafkaconnectors.kafka.strimzi.io + - kafkamirrormaker2s.kafka.strimzi.io + - kafkarebalances.kafka.strimzi.io + - strimzipodsets.core.strimzi.io + # install permissions from CSV + - apiGroups: + - "rbac.authorization.k8s.io" + resources: + # The cluster operator needs to access and manage rolebindings to grant Strimzi components cluster permissions + - rolebindings + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "rbac.authorization.k8s.io" + resources: + # The cluster operator needs to access and manage roles to grant the entity operator permissions + - roles + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "" + resources: + # The cluster operator needs to access and delete pods, this is to allow it to monitor pod health and coordinate rolling updates + - pods + # The cluster operator needs to access and manage service accounts to grant Strimzi components cluster permissions + - serviceaccounts + # The cluster operator needs to access and manage config maps for Strimzi components configuration + - configmaps + # The cluster operator needs to access and manage services and endpoints to expose Strimzi components to network traffic + - services + - endpoints + # The cluster operator needs to access and manage secrets to handle credentials + # The entity operator user-operator needs to access and manage secrets to store generated credentials + - secrets + # The cluster operator needs to access and manage persistent volume claims to bind them to Strimzi components for persistent data + - persistentvolumeclaims + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "kafka.strimzi.io" + resources: + # The Cluster Operator operates the Strimzi custom resources + - kafkas + - kafkanodepools + - kafkaconnects + - kafkaconnectors + - kafkamirrormakers + - kafkabridges + - kafkamirrormaker2s + - kafkarebalances + - kafkatopics + - kafkausers + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "kafka.strimzi.io" + resources: + # The Cluster Operator needs to manage the status of the Strimzi custom resources + - kafkas/status + - kafkanodepools/status + - kafkaconnects/status + - kafkaconnectors/status + - kafkamirrormakers/status + - kafkabridges/status + - kafkamirrormaker2s/status + - kafkarebalances/status + - kafkatopics/status + - kafkausers/status + verbs: + - get + - patch + - update + - apiGroups: + - "core.strimzi.io" + resources: + # The cluster operator uses StrimziPodSets to manage the Kafka and ZooKeeper pods + - strimzipodsets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "core.strimzi.io" + resources: + # The Cluster Operator needs to manage the status of the StrimziPodSet custom resource + - strimzipodsets/status + verbs: + - get + - patch + - update + - apiGroups: + - "kafka.strimzi.io" + resources: + # The Cluster Operator needs deletion for KafkaRebalance only (during auto-rebalancing) + - kafkarebalances + verbs: + - delete + - apiGroups: + - "apps" + resources: + # The cluster operator needs to access and manage deployments to run deployment based Strimzi components + - deployments + # The cluster operator needs to access and manage stateful sets to run stateful sets based Strimzi components + - statefulsets + # The cluster operator needs to access replica-sets to manage Strimzi components and to determine error states + - replicasets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - "apps" + resources: + # The Cluster Operator needs to scale Deployments while migrating Connect and Mirror Maker 2 clusters from Deployments to StrimziPodSets + - deployments/scale + verbs: + - get + - patch + - update + - apiGroups: + - "" # legacy core events api, used by topic operator + - "events.k8s.io" # new events api, used by cluster operator + resources: + - events + verbs: + - create + - apiGroups: + # Kafka Connect Build on OpenShift requirement + - build.openshift.io + resources: + - buildconfigs + - buildconfigs/instantiate + - builds + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - networking.k8s.io + resources: + # The cluster operator needs to access and manage network policies to lock down communication between Strimzi components + - networkpolicies + # The cluster operator needs to access and manage ingresses which allow external access to the services in a cluster + - ingresses + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - route.openshift.io + resources: + # The cluster operator needs to access and manage routes to expose Strimzi components for external access + - routes + - routes/custom-host + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - image.openshift.io + resources: + # The cluster operator needs to verify the image stream when used for Kafka Connect image build + - imagestreams + verbs: + - get + - apiGroups: + - policy + resources: + # The cluster operator needs to access and manage pod disruption budgets this limits the number of concurrent disruptions + # that a Streams component experiences, allowing for higher availability + - poddisruptionbudgets + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - coordination.k8s.io + resources: + # The cluster operator needs to access and manage leases for leader election + # The "create" verb cannot be used with "resourceNames" + - leases + verbs: + - create + - apiGroups: + - coordination.k8s.io + resources: + # The cluster operator needs to access and manage leases for leader election + - leases + resourceNames: + # The default RBAC files give the operator only access to the Lease resource names strimzi-cluster-operator + # If you want to use another resource name or resource namespace, you have to configure the RBAC resources accordingly + - strimzi-cluster-operator + verbs: + - get + - list + - watch + - delete + - patch + - update + # Cluster permissions from CSV + - apiGroups: + - "rbac.authorization.k8s.io" + resources: + # The cluster operator needs to create and manage cluster role bindings in the case of an install where a user + # has specified they want their cluster role bindings generated + - clusterrolebindings + verbs: + - get + - list + - watch + - create + - delete + - patch + - update + - apiGroups: + - storage.k8s.io + resources: + # The cluster operator requires "get" permissions to view storage class details + # This is because only a persistent volume of a supported storage class type can be resized + - storageclasses + verbs: + - get + - apiGroups: + - "" + resources: + # The cluster operator requires "list" permissions to view all nodes in a cluster + # The listing is used to determine the node addresses when NodePort access is configured + # These addresses are then exposed in the custom resource states + # The Kafka Brokers require "get" permissions to view the node they are on + # This information is used to generate a Rack ID that is used for High Availability configurations + - nodes + verbs: + - get + - list diff --git a/cluster-config/components/amq-streams-v1/base/clusterrolebinding.yaml b/cluster-config/components/amq-streams-v1/base/clusterrolebinding.yaml new file mode 100644 index 0000000..d7295fd --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: amq-streams-installer-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: amq-streams-installer-clusterrole +subjects: +- kind: ServiceAccount + name: amq-streams-installer + namespace: amq-streams-operator diff --git a/cluster-config/components/amq-streams-v1/base/kustomization.yaml b/cluster-config/components/amq-streams-v1/base/kustomization.yaml new file mode 100644 index 0000000..43f4e95 --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/kustomization.yaml @@ -0,0 +1,6 @@ +resources: +- namespace.yaml +- clusterrole.yaml +- clusterrolebinding.yaml +- serviceaccount.yaml +- clusterextension.yaml diff --git a/cluster-config/components/amq-streams-v1/base/namespace.yaml b/cluster-config/components/amq-streams-v1/base/namespace.yaml new file mode 100644 index 0000000..aa2cdf4 --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: amq-streams-operator diff --git a/cluster-config/components/amq-streams-v1/base/serviceaccount.yaml b/cluster-config/components/amq-streams-v1/base/serviceaccount.yaml new file mode 100644 index 0000000..6280615 --- /dev/null +++ b/cluster-config/components/amq-streams-v1/base/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: amq-streams-installer + namespace: amq-streams-operator diff --git a/cluster-config/components/amq-streams/base/kustomization.yaml b/cluster-config/components/amq-streams/base/kustomization.yaml new file mode 100644 index 0000000..9ad12ad --- /dev/null +++ b/cluster-config/components/amq-streams/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- subscription.yaml diff --git a/cluster-config/components/amq-streams/base/subscription.yaml b/cluster-config/components/amq-streams/base/subscription.yaml new file mode 100644 index 0000000..0da3527 --- /dev/null +++ b/cluster-config/components/amq-streams/base/subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: amq-streams + namespace: openshift-operators +spec: + channel: stable + installPlanApproval: Automatic + name: amq-streams + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/amq-streams/overlays/amq-streams-2.7.x/kustomization.yaml b/cluster-config/components/amq-streams/overlays/amq-streams-2.7.x/kustomization.yaml new file mode 100644 index 0000000..2b6f50d --- /dev/null +++ b/cluster-config/components/amq-streams/overlays/amq-streams-2.7.x/kustomization.yaml @@ -0,0 +1,11 @@ +resources: +- ../../base + +patches: + - patch: | + - op: replace + path: /spec/channel + value: 'amq-streams-2.7.x' + target: + kind: Subscription + name: amq-streams diff --git a/cluster-config/components/argo-rollouts/base/kustomization.yaml b/cluster-config/components/argo-rollouts/base/kustomization.yaml new file mode 100644 index 0000000..54c4424 --- /dev/null +++ b/cluster-config/components/argo-rollouts/base/kustomization.yaml @@ -0,0 +1,6 @@ +namespace: argo-rollouts + +resources: +- namespace.yaml +- rollouts-analysis-monitoring.yaml +- https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml diff --git a/cluster-config/components/argo-rollouts/base/namespace.yaml b/cluster-config/components/argo-rollouts/base/namespace.yaml new file mode 100644 index 0000000..1dfa470 --- /dev/null +++ b/cluster-config/components/argo-rollouts/base/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: argo-rollouts + annotations: + openshift.io/description: Argo Rollouts Progressive Delivery + openshift.io/display-name: Argo Rollouts diff --git a/cluster-config/components/argo-rollouts/base/rollouts-analysis-monitoring.yaml b/cluster-config/components/argo-rollouts/base/rollouts-analysis-monitoring.yaml new file mode 100644 index 0000000..2f6bee0 --- /dev/null +++ b/cluster-config/components/argo-rollouts/base/rollouts-analysis-monitoring.yaml @@ -0,0 +1,11 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: rollouts-analysis-monitoring +subjects: + - kind: ServiceAccount + name: argo-rollouts +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-monitoring-view diff --git a/cluster-config/components/banner/base/README.md b/cluster-config/components/banner/base/README.md new file mode 100644 index 0000000..23b8c03 --- /dev/null +++ b/cluster-config/components/banner/base/README.md @@ -0,0 +1,3 @@ +Displays a banner in the OpenShift Console with the cluster ID and name. + +Note that is leveraging ACM to populate the GitOps subscription with environment variables coupled with a plugin in Argo CD to post-process kustomize. diff --git a/cluster-config/components/banner/base/banner.yaml b/cluster-config/components/banner/base/banner.yaml new file mode 100644 index 0000000..b5440b2 --- /dev/null +++ b/cluster-config/components/banner/base/banner.yaml @@ -0,0 +1,12 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleNotification +metadata: + name: banner +spec: + text: "Cluster: ${CLUSTER_NAME}" + location: BannerTop + color: '#fff' + backgroundColor: "#${COLOR}" + link: + href: https://console.redhat.com/openshift/details/${CLUSTER_ID} + text: "(${CLUSTER_ID})" diff --git a/cluster-config/components/banner/base/kustomization.yaml b/cluster-config/components/banner/base/kustomization.yaml new file mode 100644 index 0000000..102523a --- /dev/null +++ b/cluster-config/components/banner/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- banner.yaml diff --git a/cluster-config/components/camel-k-operator/base/kustomization.yaml b/cluster-config/components/camel-k-operator/base/kustomization.yaml new file mode 100644 index 0000000..3023ff6 --- /dev/null +++ b/cluster-config/components/camel-k-operator/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- subscription.yaml diff --git a/cluster-config/components/camel-k-operator/base/subscription.yaml b/cluster-config/components/camel-k-operator/base/subscription.yaml new file mode 100644 index 0000000..973e667 --- /dev/null +++ b/cluster-config/components/camel-k-operator/base/subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: red-hat-camel-k + namespace: openshift-operators +spec: + channel: latest + installPlanApproval: Automatic + name: red-hat-camel-k + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/cert-manager-operator/aggregate/overlays/letsencrypt/kustomization.yaml b/cluster-config/components/cert-manager-operator/aggregate/overlays/letsencrypt/kustomization.yaml new file mode 100644 index 0000000..5eecc47 --- /dev/null +++ b/cluster-config/components/cert-manager-operator/aggregate/overlays/letsencrypt/kustomization.yaml @@ -0,0 +1,4 @@ +resources: +- ../../../operator/base +- ../../../instance/base +- ../../../issuers/letsencrypt-route53/base diff --git a/cluster-config/components/cert-manager-operator/instance/base/certmanager.yaml b/cluster-config/components/cert-manager-operator/instance/base/certmanager.yaml new file mode 100644 index 0000000..7b95760 --- /dev/null +++ b/cluster-config/components/cert-manager-operator/instance/base/certmanager.yaml @@ -0,0 +1,15 @@ +apiVersion: operator.openshift.io/v1alpha1 +kind: CertManager +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: cluster +spec: + logLevel: Normal + managementState: Managed + observedConfig: null + operatorLogLevel: Normal + controllerConfig: + overrideArgs: + - '--dns01-recursive-nameservers=8.8.8.8:53,8.8.4.4:53' + - '--dns01-recursive-nameservers-only' diff --git a/cluster-config/components/cert-manager-operator/instance/base/kustomization.yaml b/cluster-config/components/cert-manager-operator/instance/base/kustomization.yaml new file mode 100644 index 0000000..3a258ae --- /dev/null +++ b/cluster-config/components/cert-manager-operator/instance/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- certmanager.yaml diff --git a/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/cert-manager-ns.yaml b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/cert-manager-ns.yaml new file mode 100644 index 0000000..c90416f --- /dev/null +++ b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/cert-manager-ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: cert-manager diff --git a/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/kustomization.yaml b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/kustomization.yaml new file mode 100644 index 0000000..6c88db3 --- /dev/null +++ b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +resources: +- cert-manager-ns.yaml +- letsencrypt-aws-external.yaml +- letsencrypt-staging-cluster-issuer.yaml +- letsencrypt-prod-cluster-issuer.yaml diff --git a/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-aws-external.yaml b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-aws-external.yaml new file mode 100644 index 0000000..21ff64d --- /dev/null +++ b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-aws-external.yaml @@ -0,0 +1,15 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: letsencrypt-aws + namespace: cert-manager +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: letsencrypt-aws + data: + - secretKey: secret-access-key + remoteRef: + key: AWS_LETSENCRYPT diff --git a/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-prod-cluster-issuer.yaml b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-prod-cluster-issuer.yaml new file mode 100644 index 0000000..80098e4 --- /dev/null +++ b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-prod-cluster-issuer.yaml @@ -0,0 +1,23 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: gnunn@redhat.com + # This key doesn't exist, cert-manager creates it + privateKeySecretRef: + name: gnunn-redhat-issuer-account-key + solvers: + - selector: + dnsZones: + - "ocplab.com" + dns01: + route53: + region: ca-central-1 + accessKeyID: AKIAVW7HGAZVWLIKXRCA + hostedZoneID: Z1LKUX3GLO9GW9 + secretAccessKeySecretRef: + name: letsencrypt-aws + key: secret-access-key diff --git a/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-staging-cluster-issuer.yaml b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-staging-cluster-issuer.yaml new file mode 100644 index 0000000..92cf9bf --- /dev/null +++ b/cluster-config/components/cert-manager-operator/issuers/letsencrypt-route53/base/letsencrypt-staging-cluster-issuer.yaml @@ -0,0 +1,23 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: gnunn@redhat.com + # This key doesn't exist, cert-manager creates it + privateKeySecretRef: + name: gnunn-redhat-issuer-account-key + solvers: + - selector: + dnsZones: + - "ocplab.com" + dns01: + route53: + region: ca-central-1 + accessKeyID: AKIAVW7HGAZVWLIKXRCA + hostedZoneID: Z1LKUX3GLO9GW9 + secretAccessKeySecretRef: + name: letsencrypt-aws + key: secret-access-key diff --git a/cluster-config/components/cert-manager-operator/operator/base/kustomization.yaml b/cluster-config/components/cert-manager-operator/operator/base/kustomization.yaml new file mode 100644 index 0000000..f6a596b --- /dev/null +++ b/cluster-config/components/cert-manager-operator/operator/base/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +namespace: cert-manager-operator + +resources: +- operator-namespace.yaml +- operator-group.yaml +- subscription.yaml diff --git a/cluster-config/components/cert-manager-operator/operator/base/operator-group.yaml b/cluster-config/components/cert-manager-operator/operator/base/operator-group.yaml new file mode 100644 index 0000000..453441a --- /dev/null +++ b/cluster-config/components/cert-manager-operator/operator/base/operator-group.yaml @@ -0,0 +1,8 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-cert-manager-operator +spec: + targetNamespaces: + - cert-manager-operator + upgradeStrategy: Default diff --git a/cluster-config/components/cert-manager-operator/operator/base/operator-namespace.yaml b/cluster-config/components/cert-manager-operator/operator/base/operator-namespace.yaml new file mode 100644 index 0000000..96f3eff --- /dev/null +++ b/cluster-config/components/cert-manager-operator/operator/base/operator-namespace.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/display-name: Red Hat Certificate Manager Operator + labels: + openshift.io/cluster-monitoring: 'true' + name: cert-manager-operator diff --git a/cluster-config/components/cert-manager-operator/operator/base/subscription.yaml b/cluster-config/components/cert-manager-operator/operator/base/subscription.yaml new file mode 100644 index 0000000..d8894c6 --- /dev/null +++ b/cluster-config/components/cert-manager-operator/operator/base/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: openshift-cert-manager-operator +spec: + channel: stable-v1 + installPlanApproval: Automatic + name: openshift-cert-manager-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/certificates/base/apiserver.yaml b/cluster-config/components/certificates/base/apiserver.yaml new file mode 100644 index 0000000..e688b2e --- /dev/null +++ b/cluster-config/components/certificates/base/apiserver.yaml @@ -0,0 +1,14 @@ +apiVersion: config.openshift.io/v1 +kind: APIServer +metadata: + name: cluster + annotations: + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-options: Validate=false,ServerSideApply=true +spec: + servingCerts: + namedCertificates: + - names: + - api.${BASE_DOMAIN} + servingCertificate: + name: openshift-api-certificate diff --git a/cluster-config/components/certificates/base/ingresscontroller.yaml b/cluster-config/components/certificates/base/ingresscontroller.yaml new file mode 100644 index 0000000..26c75fc --- /dev/null +++ b/cluster-config/components/certificates/base/ingresscontroller.yaml @@ -0,0 +1,11 @@ +apiVersion: operator.openshift.io/v1 +kind: IngressController +metadata: + name: default + namespace: openshift-ingress-operator + annotations: + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-options: Validate=false,ServerSideApply=true +spec: + defaultCertificate: + name: openshift-wildcard-certificate diff --git a/cluster-config/components/certificates/base/kustomization.yaml b/cluster-config/components/certificates/base/kustomization.yaml new file mode 100644 index 0000000..af999a9 --- /dev/null +++ b/cluster-config/components/certificates/base/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - openshift-api-certificate.yaml + - openshift-wildcard-certificate.yaml + - apiserver.yaml + - ingresscontroller.yaml diff --git a/cluster-config/components/certificates/base/openshift-api-certificate.yaml b/cluster-config/components/certificates/base/openshift-api-certificate.yaml new file mode 100644 index 0000000..2083286 --- /dev/null +++ b/cluster-config/components/certificates/base/openshift-api-certificate.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: openshift-api + namespace: openshift-config + annotations: + argocd.argoproj.io/sync-wave: '0' +spec: + secretName: openshift-api-certificate + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - api.${BASE_DOMAIN} diff --git a/cluster-config/components/certificates/base/openshift-wildcard-certificate.yaml b/cluster-config/components/certificates/base/openshift-wildcard-certificate.yaml new file mode 100644 index 0000000..d3de941 --- /dev/null +++ b/cluster-config/components/certificates/base/openshift-wildcard-certificate.yaml @@ -0,0 +1,15 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: openshift-wildcard + namespace: openshift-ingress + annotations: + argocd.argoproj.io/sync-wave: '0' +spec: + secretName: openshift-wildcard-certificate + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + commonName: '*.${SUB_DOMAIN}' + dnsNames: + - '*.${SUB_DOMAIN}' diff --git a/cluster-config/components/clean-completed-pods/base/README.md b/cluster-config/components/clean-completed-pods/base/README.md new file mode 100644 index 0000000..c76b8bc --- /dev/null +++ b/cluster-config/components/clean-completed-pods/base/README.md @@ -0,0 +1,3 @@ +Cronjob that periodically removes completed jobs, based on KCS here: + +https://access.redhat.com/solutions/6934861 diff --git a/cluster-config/components/clean-completed-pods/base/clean-completed-pods-cronjob.yaml b/cluster-config/components/clean-completed-pods/base/clean-completed-pods-cronjob.yaml new file mode 100644 index 0000000..e020efe --- /dev/null +++ b/cluster-config/components/clean-completed-pods/base/clean-completed-pods-cronjob.yaml @@ -0,0 +1,40 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: completed-pod-cleanup +spec: + jobTemplate: + metadata: + name: completed-pod-cleanup + spec: + template: + spec: + containers: + - command: + - /bin/bash + - -c + - | + set -euo pipefail + echo "// Listed Completed Pod." + oc get pods -o wide --all-namespaces --sort-by='{.metadata.creationTimestamp}','{.metadata.namespace}','{.metadata.name}' --field-selector=status.phase==Succeeded + COMPLETED_POD=`oc get pods -o jsonpath="{range .items[*]}{.metadata.namespace}{'\t'}{.metadata.name}{'\n'}{end}" --all-namespaces --field-selector=metadata.namespace!=ocp-completed-pod-cleanup,status.phase==Succeeded` + if [ -n "$COMPLETED_POD" ]; then + echo "// Deleted Completed Pod." + while read NS_NAME POD_NAME + do + oc -n $NS_NAME delete pod $POD_NAME; + done <<< "$COMPLETED_POD" + fi + image: registry.redhat.io/openshift4/ose-cli:latest # change the image in disconnected environment + imagePullPolicy: IfNotPresent + name: completed-pod-cleanup + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: OnFailure + serviceAccount: completed-pod-cleanup + serviceAccountName: completed-pod-cleanup + terminationGracePeriodSeconds: 30 + schedule: "0 11 * * *" + suspend: false +status: {} diff --git a/cluster-config/components/clean-completed-pods/base/kustomization.yaml b/cluster-config/components/clean-completed-pods/base/kustomization.yaml new file mode 100644 index 0000000..3962a74 --- /dev/null +++ b/cluster-config/components/clean-completed-pods/base/kustomization.yaml @@ -0,0 +1,6 @@ +namespace: clean-completed-pods + +resources: + - namespace.yaml + - clean-completed-pods-cronjob.yaml + - sa-rbac.yaml diff --git a/cluster-config/components/clean-completed-pods/base/namespace.yaml b/cluster-config/components/clean-completed-pods/base/namespace.yaml new file mode 100644 index 0000000..969d872 --- /dev/null +++ b/cluster-config/components/clean-completed-pods/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: clean-completed-pods diff --git a/cluster-config/components/clean-completed-pods/base/sa-rbac.yaml b/cluster-config/components/clean-completed-pods/base/sa-rbac.yaml new file mode 100644 index 0000000..ce391bc --- /dev/null +++ b/cluster-config/components/clean-completed-pods/base/sa-rbac.yaml @@ -0,0 +1,31 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: completed-pod-cleanup + labels: + app: completed-pod-cleanup +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cluster-completed-pod-cleanup +rules: + - apiGroups: [""] + resources: + - "pods" + verbs: ["get", "list", "create", "delete", "watch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: completed-pod-cleanup + labels: + app: completed-pod-cleanup +subjects: + - kind: ServiceAccount + name: completed-pod-cleanup + namespace: clean-completed-pods +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-completed-pod-cleanup diff --git a/cluster-config/components/codeready-workspaces/base/codeready-workspaces-cr.yaml b/cluster-config/components/codeready-workspaces/base/codeready-workspaces-cr.yaml new file mode 100644 index 0000000..b922ec5 --- /dev/null +++ b/cluster-config/components/codeready-workspaces/base/codeready-workspaces-cr.yaml @@ -0,0 +1,15 @@ +apiVersion: org.eclipse.che/v1 +kind: CheCluster +metadata: + name: codeready-workspaces + namespace: openshift-workspaces +spec: + auth: + identityProviderURL: 'https://sso-sso.apps.home.ocplab.com' + identityProviderRealm: openshift + identityProviderClientId: codeready-public + externalIdentityProvider: true + server: + selfSignedCert: false + gitSelfSignedCert: false + tlsSupport: true diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance-master-only/kustomization.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance-master-only/kustomization.yaml new file mode 100644 index 0000000..d1f360d --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance-master-only/kustomization.yaml @@ -0,0 +1,5 @@ +resources: +- ../cis-compliance + +patchesStrategicMerge: +- patch-scansetting.yaml diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance-master-only/patch-scansetting.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance-master-only/patch-scansetting.yaml new file mode 100644 index 0000000..5c2abff --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance-master-only/patch-scansetting.yaml @@ -0,0 +1,8 @@ +apiVersion: compliance.openshift.io/v1alpha1 +debug: true +kind: ScanSetting +metadata: + name: cis-compliance + namespace: openshift-compliance +roles: +- master diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance/cis-compliance-scan-setting-binding.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance/cis-compliance-scan-setting-binding.yaml new file mode 100644 index 0000000..73e8197 --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance/cis-compliance-scan-setting-binding.yaml @@ -0,0 +1,19 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ScanSettingBinding +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "1" + name: cis-compliance + namespace: openshift-compliance +profiles: +- apiGroup: compliance.openshift.io/v1alpha1 + kind: TailoredProfile + name: ocp4-cis-node-lab +- apiGroup: compliance.openshift.io/v1alpha1 + kind: TailoredProfile + name: ocp4-cis-lab +settingsRef: + apiGroup: compliance.openshift.io/v1alpha1 + kind: ScanSetting + name: default diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance/cis-compliance-scansetting.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance/cis-compliance-scansetting.yaml new file mode 100644 index 0000000..e7811e2 --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance/cis-compliance-scansetting.yaml @@ -0,0 +1,37 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: ScanSetting +metadata: + name: cis-compliance + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "1" +rawResultStorage: + nodeSelector: + node-role.kubernetes.io/master: "" + pvAccessModes: + - ReadWriteOnce + rotation: 3 + size: 1Gi + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/not-ready + operator: Exists + tolerationSeconds: 300 + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 300 + - effect: NoSchedule + key: node.kubernetes.io/memory-pressure + operator: Exists +roles: +- master +- worker +scanTolerations: +- operator: Exists +schedule: 0 */3 * * * +showNotApplicable: false +strictNodeScan: true diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance/kustomization.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance/kustomization.yaml new file mode 100644 index 0000000..8675404 --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance/kustomization.yaml @@ -0,0 +1,27 @@ +# Assumes the cluster admin had pre-created the sealed-secrets project and secret. +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-compliance + +resources: +- github.com/redhat-cop/gitops-catalog/compliance-operator/operator/overlays/release-0.1 +- ocp-cis-tailored-profile.yaml +- ocp-cis-node-tailored-profile.yaml +- cis-compliance-scan-setting-binding.yaml +- cis-compliance-scansetting.yaml + +patches: +- patch: |- + - op: add + path: /metadata/labels + value: {"openshift.io/cluster-monitoring": "true"} + target: + kind: Namespace +- patch: |- + - op: replace + path: /spec/channel + value: stable + target: + kind: Subscription + name: compliance-operator diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance/ocp-cis-node-tailored-profile.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance/ocp-cis-node-tailored-profile.yaml new file mode 100644 index 0000000..042ea27 --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance/ocp-cis-node-tailored-profile.yaml @@ -0,0 +1,18 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: TailoredProfile +metadata: + name: ocp4-cis-node-lab + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "1" +spec: + extends: ocp4-cis-node + description: Lab CIS node profile + title: Lab CIS node profile + disableRules: + - name: ocp4-file-permissions-etcd-data-dir + rationale: Default value of `drwxr-xr-x.` is fine + - name: ocp4-kubelet-enable-protect-kernel-defaults + rationale: Not applicable + - name: ocp4-kubelet-enable-protect-kernel-sysctl + rationale: Not applicable diff --git a/cluster-config/components/compliance-operator/overlays/cis-compliance/ocp-cis-tailored-profile.yaml b/cluster-config/components/compliance-operator/overlays/cis-compliance/ocp-cis-tailored-profile.yaml new file mode 100644 index 0000000..62aa321 --- /dev/null +++ b/cluster-config/components/compliance-operator/overlays/cis-compliance/ocp-cis-tailored-profile.yaml @@ -0,0 +1,38 @@ +apiVersion: compliance.openshift.io/v1alpha1 +kind: TailoredProfile +metadata: + name: ocp4-cis-lab + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "1" +spec: + extends: ocp4-cis + description: Lab CIS profile + title: Lab CIS profile + disableRules: + - name: ocp4-api-server-encryption-provider-cipher + rationale: Using letsencrypt certificates, not applicable + - name: ocp4-audit-log-forwarding-enabled + rationale: Homelab so no log forwarding available + - name: ocp4-scc-limit-container-allowed-capabilities + rationale: Some containers require extra privileges + - name: ocp4-configure-network-policies-namespaces + rationale: Home lab supports ad-hoc demos + - name: ocp4-api-server-audit-log-maxsize + rationale: Home lab, no need for auditing + - name: ocp4-ocp-api-server-audit-log-maxsize + rationale: Home lab, no need for auditing + - name: ocp4-audit-profile-set + rationale: Home lab, default auditing is sufficient + - name: ocp4-ocp-allowed-registries + rationale: Home lab, open registries is fine + - name: ocp4-ocp-allowed-registries-for-import + rationale: Home lab, open registries is fine + - name: ocp4-api-server-api-priority-gate-enabled + rationale: Need to understand mis-behaving clients in Home lab + - name: ocp4-kubelet-configure-tls-cipher-suites-ingresscontroller + rationale: Home lab + - name: ocp4-api-server-tls-cipher-suites + rationale: Home lab + - name: ocp4-kubelet-configure-tls-cipher-suites + rationale: Home lab diff --git a/cluster-config/components/consolelinks/base/kustomization.yaml b/cluster-config/components/consolelinks/base/kustomization.yaml new file mode 100644 index 0000000..87f79bc --- /dev/null +++ b/cluster-config/components/consolelinks/base/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- quay-link.yaml +- sso-link.yaml diff --git a/cluster-config/components/consolelinks/base/quay-link.yaml b/cluster-config/components/consolelinks/base/quay-link.yaml new file mode 100644 index 0000000..f9b6888 --- /dev/null +++ b/cluster-config/components/consolelinks/base/quay-link.yaml @@ -0,0 +1,11 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: quay +spec: + href: 'https://quay.io/repository' + location: ApplicationMenu + text: Quay + applicationMenu: + section: Tools + imageURL: https://quay.io/static/img/quay_favicon.png diff --git a/cluster-config/components/consolelinks/base/sso-link.yaml b/cluster-config/components/consolelinks/base/sso-link.yaml new file mode 100644 index 0000000..0184db2 --- /dev/null +++ b/cluster-config/components/consolelinks/base/sso-link.yaml @@ -0,0 +1,8 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: sso-account +spec: + href: 'https://sso.ocplab.com/realms/ocplab/account' + location: UserMenu + text: Account Settings diff --git a/cluster-config/components/container-security-operator/base/kustomization.yaml b/cluster-config/components/container-security-operator/base/kustomization.yaml new file mode 100644 index 0000000..9ad12ad --- /dev/null +++ b/cluster-config/components/container-security-operator/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- subscription.yaml diff --git a/cluster-config/components/container-security-operator/base/subscription.yaml b/cluster-config/components/container-security-operator/base/subscription.yaml new file mode 100644 index 0000000..0a758c6 --- /dev/null +++ b/cluster-config/components/container-security-operator/base/subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: container-security-operator + namespace: openshift-operators +spec: + channel: stable-3.7 + installPlanApproval: Automatic + name: container-security-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/container-security-operator/overlays/stable-3.10/kustomization.yaml b/cluster-config/components/container-security-operator/overlays/stable-3.10/kustomization.yaml new file mode 100644 index 0000000..db900ff --- /dev/null +++ b/cluster-config/components/container-security-operator/overlays/stable-3.10/kustomization.yaml @@ -0,0 +1,11 @@ +resources: +- ../../base + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: 'stable-3.10' + target: + kind: Subscription + name: container-security-operator diff --git a/cluster-config/components/container-security-operator/overlays/stable-3.13/kustomization.yaml b/cluster-config/components/container-security-operator/overlays/stable-3.13/kustomization.yaml new file mode 100644 index 0000000..2a6368f --- /dev/null +++ b/cluster-config/components/container-security-operator/overlays/stable-3.13/kustomization.yaml @@ -0,0 +1,11 @@ +resources: +- ../../base + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: 'stable-3.13' + target: + kind: Subscription + name: container-security-operator diff --git a/cluster-config/components/container-security-operator/overlays/stable-3.9/kustomization.yaml b/cluster-config/components/container-security-operator/overlays/stable-3.9/kustomization.yaml new file mode 100644 index 0000000..3719dd2 --- /dev/null +++ b/cluster-config/components/container-security-operator/overlays/stable-3.9/kustomization.yaml @@ -0,0 +1,11 @@ +resources: +- ../../base + +patches: + - patch: |- + - op: replace + path: /spec/channel + value: 'stable-3.9' + target: + kind: Subscription + name: container-security-operator diff --git a/cluster-config/components/defrag-etcd/base/cronjob.yaml b/cluster-config/components/defrag-etcd/base/cronjob.yaml new file mode 100644 index 0000000..9d30471 --- /dev/null +++ b/cluster-config/components/defrag-etcd/base/cronjob.yaml @@ -0,0 +1,25 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: defrag-etcd +spec: + schedule: "0 11 * * *" + jobTemplate: + spec: + template: + spec: + containers: + - name: defrag-etcd + image: registry.redhat.io/openshift4/ose-cli:latest + imagePullPolicy: IfNotPresent + command: + - /bin/bash + - -c + - | + #!/usr/bin/env bash + + oc get pods -l app=etcd -n openshift-etcd --no-headers -o custom-columns=":metadata.name" | while read -r pod ; do + oc exec -n openshift-etcd $pod --container etcdctl -- sh -c "unset ETCDCTL_ENDPOINTS && etcdctl --command-timeout=30s --endpoints=https://localhost:2379 defrag" + done + serviceAccountName: defrag-etcd + restartPolicy: OnFailure diff --git a/cluster-config/components/defrag-etcd/base/kustomization.yaml b/cluster-config/components/defrag-etcd/base/kustomization.yaml new file mode 100644 index 0000000..498cbad --- /dev/null +++ b/cluster-config/components/defrag-etcd/base/kustomization.yaml @@ -0,0 +1,5 @@ +namespace: openshift-etcd + +resources: +- sa-rbac.yaml +- cronjob.yaml diff --git a/cluster-config/components/defrag-etcd/base/sa-rbac.yaml b/cluster-config/components/defrag-etcd/base/sa-rbac.yaml new file mode 100644 index 0000000..2ae7299 --- /dev/null +++ b/cluster-config/components/defrag-etcd/base/sa-rbac.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: defrag-etcd +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: defrag-etcd +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - exec + - apiGroups: + - "" + resources: + - pods/exec + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: defrag-etcd +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: defrag-etcd +subjects: + - kind: ServiceAccount + name: defrag-etcd diff --git a/cluster-config/components/dev-console-plugin/base/kustomization.yaml b/cluster-config/components/dev-console-plugin/base/kustomization.yaml new file mode 100644 index 0000000..0abe540 --- /dev/null +++ b/cluster-config/components/dev-console-plugin/base/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- namespace.yaml + +helmGlobals: + chartHome: charts/openshift-console-plugin + +helmCharts: +- name: openshift-console-plugin + version: 0.3.0 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: dev-console-plugin + releaseName: dev-console-plugin diff --git a/cluster-config/components/dev-console-plugin/base/namespace.yaml b/cluster-config/components/dev-console-plugin/base/namespace.yaml new file mode 100644 index 0000000..2aa549c --- /dev/null +++ b/cluster-config/components/dev-console-plugin/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: dev-console-plugin diff --git a/cluster-config/components/dev-console-plugin/base/values.yaml b/cluster-config/components/dev-console-plugin/base/values.yaml new file mode 100644 index 0000000..5d4a5b2 --- /dev/null +++ b/cluster-config/components/dev-console-plugin/base/values.yaml @@ -0,0 +1,4 @@ +plugin: + name: dev-console-plugin + namespace: dev-console-plugin + image: quay.io/gnunn/dev-console-plugin:latest diff --git a/cluster-config/components/dev-tools/overlays/default/configure-sonarqube-job.yaml b/cluster-config/components/dev-tools/overlays/default/configure-sonarqube-job.yaml new file mode 100644 index 0000000..8591e3d --- /dev/null +++ b/cluster-config/components/dev-tools/overlays/default/configure-sonarqube-job.yaml @@ -0,0 +1,33 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: configure-sonarqube +spec: + template: + spec: + containers: + - image: registry.access.redhat.com/ubi8/ubi:8.3 + command: + - /bin/bash + - -c + - | + curl -H 'Cache-Control: no-cache' -o /tmp/sonarqube-plugins -s ${SCRIPT_URL}; + chmod +x /tmp/sonarqube-plugins; + /tmp/sonarqube-plugins + imagePullPolicy: Always + name: configure-sonarqube + env: + - name: SONARQUBE_PLUGINS + value: "java,javascript,dependencycheck,jacoco,pmd,scmgit" + - name: SONARQUBE_PASSWORD + valueFrom: + secretKeyRef: + name: sonarqube-admin + key: password + - name: SCRIPT_URL + value: "https://raw.githubusercontent.com/gnunn-gitops/cluster-config/main/components/dev-tools/scripts/sonarqube-config" + dnsPolicy: ClusterFirst + restartPolicy: OnFailure + serviceAccount: default + serviceAccountName: default + terminationGracePeriodSeconds: 30 diff --git a/cluster-config/components/dev-tools/overlays/default/kustomization.yaml b/cluster-config/components/dev-tools/overlays/default/kustomization.yaml new file mode 100644 index 0000000..3934927 --- /dev/null +++ b/cluster-config/components/dev-tools/overlays/default/kustomization.yaml @@ -0,0 +1,48 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: dev-tools + +bases: +# Nexus +- https://github.com/redhat-cop/gitops-catalog/nexus2/base +# Sonarqube +- sonarqube-admin-secret.yaml +- https://github.com/redhat-cop/gitops-catalog/sonarqube8/base +- configure-sonarqube-job.yaml + +resources: +- namespace.yaml + +patches: +- patch: |- + - op: replace + path: /spec/template/spec/containers/0/image + value: sonarqube:lts-community + target: + kind: Deployment + name: sonarqube +- patch: |- + - op: add + path: /spec/template/spec/containers/0/env + value: + - name: SONAR_JDBC_PASSWORD + value: kHPdpIYtdtGXeStv + - name: SONAR_JDBC_URL + value: 'jdbc:postgresql://postgresql-sonarqube/sonar' + - name: SONAR_JDBC_USERNAME + value: sonar + - name: SONAR_TELEMETRY_ENABLE + value: 'false' + - name: SONAR_PLUGINS_RISK_CONSENT + value: ACCEPTED + target: + kind: Deployment + name: sonarqube +- patch: |- + - op: add + path: /spec/tls + value: + termination: edge + target: + kind: Route diff --git a/cluster-config/components/dev-tools/overlays/default/namespace.yaml b/cluster-config/components/dev-tools/overlays/default/namespace.yaml new file mode 100644 index 0000000..591ff7f --- /dev/null +++ b/cluster-config/components/dev-tools/overlays/default/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/description: Project for development tools like nexus and sonarqube + openshift.io/display-name: Development Tools + name: dev-tools diff --git a/cluster-config/components/dev-tools/overlays/default/sonarqube-admin-secret.yaml b/cluster-config/components/dev-tools/overlays/default/sonarqube-admin-secret.yaml new file mode 100644 index 0000000..8a32b78 --- /dev/null +++ b/cluster-config/components/dev-tools/overlays/default/sonarqube-admin-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: sonarqube-admin + namespace: dev-tools +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: sonarqube-admin + data: + - secretKey: password + remoteRef: + key: SONARQUBE_ADMIN_PASSWORD diff --git a/cluster-config/components/dev-tools/scripts/sonarqube-config b/cluster-config/components/dev-tools/scripts/sonarqube-config new file mode 100644 index 0000000..744f02a --- /dev/null +++ b/cluster-config/components/dev-tools/scripts/sonarqube-config @@ -0,0 +1,27 @@ +SONARQUBE_HOST=sonarqube:9000 + +echo "Waiting for sonarqube to be ready..." + +until [ "$(curl --silent --show-error --connect-timeout 1 http://${SONARQUBE_HOST}/api/system/status | grep 'UP')" ]; +do + sleep 5 +done +echo "SonarQube reporting UP. Wait 5 seconds to be sure." +sleep 5 + +echo "Updating admin password on host ${SONARQUBE_HOST}" +curl -u admin:admin -X POST "http://${SONARQUBE_HOST}/api/users/change_password?login=admin&previousPassword=admin&password=${SONARQUBE_PASSWORD}" + +echo "Disabling force authentication for demo purposes" +curl -u admin:${SONARQUBE_PASSWORD} --request POST "http://sonarqube:9000/api/settings/set?key=sonar.forceAuthentication&value=false" + +echo "Installing plugins ${SONARQUBE_PLUGINS} on server ${SONARQUBE_HOST}" + +for i in ${SONARQUBE_PLUGINS//,/ } +do + echo "Installing $i" + curl -u admin:${SONARQUBE_PASSWORD} --data "key=$i" http://${SONARQUBE_HOST}/api/plugins/install +done + +echo "Restarting server ${SONARQUBE_HOST} ..." +curl -u admin:${SONARQUBE_PASSWORD} -X POST http://${SONARQUBE_HOST}/api/system/restart diff --git a/cluster-config/components/eso/instance/base/kustomization.yaml b/cluster-config/components/eso/instance/base/kustomization.yaml new file mode 100644 index 0000000..22bf756 --- /dev/null +++ b/cluster-config/components/eso/instance/base/kustomization.yaml @@ -0,0 +1,7 @@ +namespace: external-secrets + +resources: +- namespace.yaml +- operatorconfig.yaml +- podmonitor.yaml +- prometheus-rule.yaml diff --git a/cluster-config/components/eso/instance/base/namespace.yaml b/cluster-config/components/eso/instance/base/namespace.yaml new file mode 100644 index 0000000..4ef398e --- /dev/null +++ b/cluster-config/components/eso/instance/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: external-secrets diff --git a/cluster-config/components/eso/instance/base/operatorconfig.yaml b/cluster-config/components/eso/instance/base/operatorconfig.yaml new file mode 100644 index 0000000..da142dd --- /dev/null +++ b/cluster-config/components/eso/instance/base/operatorconfig.yaml @@ -0,0 +1,22 @@ +apiVersion: operator.external-secrets.io/v1alpha1 +kind: OperatorConfig +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "1" + name: cluster +spec: + crds: + conversion: + enabled: false + prometheus: + enabled: true + service: + port: 8080 + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 100m + memory: 256Mi diff --git a/cluster-config/components/eso/instance/base/podmonitor.yaml b/cluster-config/components/eso/instance/base/podmonitor.yaml new file mode 100644 index 0000000..1664083 --- /dev/null +++ b/cluster-config/components/eso/instance/base/podmonitor.yaml @@ -0,0 +1,27 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: external-secrets-controller + namespace: external-secrets + labels: + app.kubernetes.io/name: external-secrets-cert-controller +spec: + selector: + matchLabels: + app.kubernetes.io/name: external-secrets-cert-controller + podMetricsEndpoints: + - port: metrics +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: external-secrets + namespace: external-secrets + labels: + app.kubernetes.io/name: external-secrets +spec: + selector: + matchLabels: + app.kubernetes.io/name: external-secrets + podMetricsEndpoints: + - port: metrics diff --git a/cluster-config/components/eso/instance/base/prometheus-rule.yaml b/cluster-config/components/eso/instance/base/prometheus-rule.yaml new file mode 100644 index 0000000..8c461dd --- /dev/null +++ b/cluster-config/components/eso/instance/base/prometheus-rule.yaml @@ -0,0 +1,20 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: external-secrets + namespace: external-secrets +spec: + groups: + - name: ExternalSecrets + rules: + - alert: ExternalSecretSyncError + annotations: + description: |- + The external secret {{ $labels.exported_namespace }}/{{ $labels.name }} failed to synced. + Use this command to check the status: + oc get externalsecret {{ $labels.name }} -n {{ $labels.exported_namespace }} + summary: External secret failed to sync + labels: + severity: warning + expr: externalsecret_status_condition{status="False"} == 1 + for: 5m diff --git a/cluster-config/components/eso/operator/base/kustomization.yaml b/cluster-config/components/eso/operator/base/kustomization.yaml new file mode 100644 index 0000000..cb95cab --- /dev/null +++ b/cluster-config/components/eso/operator/base/kustomization.yaml @@ -0,0 +1,7 @@ +namespace: external-secrets-operator + +resources: +- namespace.yaml +- operatorgroup.yaml +- subscription.yaml +- github.com/redhat-cop/gitops-catalog/installplan-approver/base diff --git a/cluster-config/components/eso/operator/base/namespace.yaml b/cluster-config/components/eso/operator/base/namespace.yaml new file mode 100644 index 0000000..05a6acc --- /dev/null +++ b/cluster-config/components/eso/operator/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: external-secrets-operator diff --git a/cluster-config/components/eso/operator/base/operatorgroup.yaml b/cluster-config/components/eso/operator/base/operatorgroup.yaml new file mode 100644 index 0000000..8a0cefd --- /dev/null +++ b/cluster-config/components/eso/operator/base/operatorgroup.yaml @@ -0,0 +1,6 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: external-secrets-operator +spec: + upgradeStrategy: Default diff --git a/cluster-config/components/eso/operator/base/subscription.yaml b/cluster-config/components/eso/operator/base/subscription.yaml new file mode 100644 index 0000000..3e4d375 --- /dev/null +++ b/cluster-config/components/eso/operator/base/subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: external-secrets-operator + namespace: openshift-operators +spec: + channel: stable + installPlanApproval: Manual + name: external-secrets-operator + source: community-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/eso/overlays/aggregate/kustomization.yaml b/cluster-config/components/eso/overlays/aggregate/kustomization.yaml new file mode 100644 index 0000000..0716a03 --- /dev/null +++ b/cluster-config/components/eso/overlays/aggregate/kustomization.yaml @@ -0,0 +1,9 @@ +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 + +commonAnnotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + +resources: +- ../../operator/base +- ../../instance/base diff --git a/cluster-config/components/gitops-admin-plugin/base/kustomization.yaml b/cluster-config/components/gitops-admin-plugin/base/kustomization.yaml new file mode 100644 index 0000000..6b43d9a --- /dev/null +++ b/cluster-config/components/gitops-admin-plugin/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - github.com/gnunn-gitops/gitops-admin-plugin/manifests/overlays/install?ref=4.16 diff --git a/cluster-config/components/gitops-operator/base/argocd-dex-server-rolebinding.yaml b/cluster-config/components/gitops-operator/base/argocd-dex-server-rolebinding.yaml new file mode 100644 index 0000000..203610b --- /dev/null +++ b/cluster-config/components/gitops-operator/base/argocd-dex-server-rolebinding.yaml @@ -0,0 +1,11 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: argocd-dex-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argocd-argocd-server +subjects: + - kind: ServiceAccount + name: argocd-argocd-dex-server diff --git a/cluster-config/components/gitops-operator/base/argocd-external-secret.yaml b/cluster-config/components/gitops-operator/base/argocd-external-secret.yaml new file mode 100644 index 0000000..1aea3fb --- /dev/null +++ b/cluster-config/components/gitops-operator/base/argocd-external-secret.yaml @@ -0,0 +1,19 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: argocd-secret +spec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: OIDC_ARGOCD + secretKey: oidc.keycloak.clientSecret + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + creationPolicy: Merge + deletionPolicy: Retain + name: argocd-secret diff --git a/cluster-config/components/gitops-operator/base/create-pipeline-local-user-job.yaml b/cluster-config/components/gitops-operator/base/create-pipeline-local-user-job.yaml new file mode 100644 index 0000000..4e90cd8 --- /dev/null +++ b/cluster-config/components/gitops-operator/base/create-pipeline-local-user-job.yaml @@ -0,0 +1,67 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-pipeline-local-user + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + template: + spec: + containers: + - image: registry.redhat.io/openshift-gitops-1/argocd-rhel8:1.7 + command: + - /bin/bash + - -c + - | + export HOME=/home/argocd + + echo "Getting argocd admin credential..." + if kubectl get secret argocd-cluster >/dev/null; + then + # Retrieve password + PASSWORD=$(oc get secret argocd-cluster -o jsonpath="{.data.admin\.password}" | base64 -d) + else + echo "Could not retrieve admin password" + exit 1 + fi + + IFS=' ' + read -ra LIST <<< "$ACCOUNTS_NAMESPACES" + for i in "${LIST[@]}"; do # access each element of array + echo "Generating token for $i" + account=${i%%=*} + namespace=${i#*=} + HAS_SECRET=$(kubectl get secret argocd-env-secret -n $namespace --ignore-not-found) + if [ -z "$HAS_SECRET" ]; + then + echo "No argo-env-secret present, creating" + argocd login --plaintext --username admin --password ${PASSWORD} argocd-server + echo "Generating token for ${account}" + TOKEN=$(argocd account generate-token --account ${account}) + if [ "$TOKEN" ]; + then + echo "Creating secret argocd-env-secret in namespace ${namespace}" + kubectl create secret generic argocd-env-secret --from-literal=ARGOCD_AUTH_TOKEN=${TOKEN} --from-literal=ARGOCD_USERNAME=${account} --from-literal=ARGOCD_SERVER=${ARGO_SERVER_HOST} -n ${namespace} + else + echo "Token $TOKEN could not be generated, no secret created" + exit 1 + fi + else + echo "The secret argocd-env-secret already exists, skipping" + fi + done + env: + # The account namespace where the token needs to be deployed to + # Example value: product-catalog-pipeline=product-catalog-cicd demo-pipeline=demo-cicd + - name: ACCOUNTS_NAMESPACES + value: "" + - name: ARGO_SERVER_HOST + value: "" + imagePullPolicy: Always + name: create-pipeline-local-user + serviceAccount: argocd-argocd-application-controller + serviceAccountName: argocd-argocd-application-controller + dnsPolicy: ClusterFirst + restartPolicy: OnFailure + terminationGracePeriodSeconds: 30 diff --git a/cluster-config/components/gitops-operator/base/gitops-operator-cr.yaml b/cluster-config/components/gitops-operator/base/gitops-operator-cr.yaml new file mode 100644 index 0000000..f6ebf55 --- /dev/null +++ b/cluster-config/components/gitops-operator/base/gitops-operator-cr.yaml @@ -0,0 +1,254 @@ +apiVersion: argoproj.io/v1beta1 +kind: ArgoCD +metadata: + name: argocd +spec: + # using this in conjunction with respectRBAC + # defaultClusterScopedRoleDisabled: true + resourceTrackingMethod: annotation + applicationSet: {} + kustomizeBuildOptions: "--enable-helm" + notifications: + enabled: true + controller: + logLevel: debug + repo: + sidecarContainers: + - name: setenv-plugin + command: [/var/run/argocd/argocd-cmp-server] + env: + - name: KUSTOMIZE_PLUGIN_HOME + value: /etc/kustomize/plugin + - name: SUB_DOMAIN + value: ${SUB_DOMAIN} + image: quay.io/gnunn/tools:latest + imagePullPolicy: Always + securityContext: + runAsNonRoot: true + volumeMounts: + - mountPath: /var/run/argocd + name: var-files + - mountPath: /home/argocd/cmp-server/plugins + name: plugins + - mountPath: /tmp + name: tmp + - mountPath: /home/argocd/cmp-server/config/plugin.yaml + subPath: plugin.yaml + name: setenv-cmp-plugin + volumes: + - configMap: + name: setenv-cmp-plugin + name: setenv-cmp-plugin + server: + enableRolloutsUI: true + insecure: true + route: + enabled: true + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect + volumeMounts: + - mountPath: /tmp/extensions/ + name: extensions + volumes: + - emptyDir: {} + name: extensions + resourceHealthChecks: + - group: argoproj.io + kind: Application + check: | + hs = {} + hs.status = "Progressing" + hs.message = "" + if obj.status ~= nil then + if obj.status.health ~= nil then + hs.status = obj.status.health.status + hs.message = obj.status.health.message + end + end + return hs + - group: argoproj.io + kind: RolloutManager + check: | + hs = {} + if obj.status ~= nil then + if obj.status.conditions ~= nil then + for _, condition in ipairs(obj.status.conditions) do + hs.message = condition.message + break + end + end + if obj.status.phase ~= nil then + if obj.status.phase == "Failure" then + hs.status = "Degraded" + return hs + elseif obj.status.phase == "Available" then + hs.status = "Healthy" + return hs + elseif obj.status.phase == "Pending" then + hs.status = "Progressing" + return hs + end + end + hs.status = "Progressing" + hs.message = "Waiting for operator to update status" + return hs + end + - group: operators.coreos.com + kind: Subscription + check: | + health_status = {} + if obj.status ~= nil then + if obj.status.conditions ~= nil then + numDegraded = 0 + numPending = 0 + numSuspended = 0 + msg = "" + for i, condition in pairs(obj.status.conditions) do + msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. " | " .. condition.reason .. "\n" + if condition.type == "InstallPlanPending" and condition.status == "True" then + if condition.reason == "RequiresApproval" then + numSuspended = numSuspended + 1 + else + numPending = numPending + 1 + end + elseif (condition.type == "InstallPlanMissing" and condition.reason ~= "ReferencedInstallPlanNotFound") then + numDegraded = numDegraded + 1 + elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanFailed") and condition.status == "True" then + numDegraded = numDegraded + 1 + elseif (condition.type == "ResolutionFailed" and condition.reason ~= "ConstraintsNotSatisfiable") then + numDegraded = numDegraded + 1 + end + end + if numDegraded > 0 then + health_status.status = "Degraded" + health_status.message = msg + return health_status + elseif numSuspended > 0 then + health_status.status = "Suspended" + health_status.message = "Requires Approval" + return health_status + elseif numPending > 0 then + health_status.status = "Progressing" + health_status.message = "An install plan for a subscription is pending installation" + return health_status + else + health_status.status = "Healthy" + health_status.message = msg + return health_status + end + end + end + health_status.status = "Progressing" + health_status.message = "An install plan for a subscription is pending installation" + return health_status + - group: operators.coreos.com + kind: InstallPlan + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Complete" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + elseif obj.status.phase == "RequiresApproval" then + hs.status = "Suspended" + hs.message = obj.status.phase + return hs + else + hs.status = "Progressing" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for InstallPlan to complete" + return hs + - group: image.openshift.io + kind: ImageStream + check: | + hs = {} + hs.status = "Progressing" + hs.message = "" + if obj.status ~= nil then + if obj.status.tags ~= nil then + numTags = 0 + for _ , item in pairs(obj.status.tags) do + numTags = numTags + 1 + numItems = 0 + if item.tags ~= nil then + for _ , item in pairs(item.tags) do + numItems = numItems + 1 + end + if numItems == 0 then + return hs + end + end + end + if numTags > 0 then + hs.status = "Healthy" + hs.message = "ImageStream has tags resolved" + return hs + end + end + end + return hs + - group: build.openshift.io + kind: Build + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Complete" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for Build to complete" + return hs + - kind: PersistentVolumeClaim + check: | + hs = {} + if obj.status ~= nil then + if obj.status.phase ~= nil then + if obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + if obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = obj.status.phase + return hs + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for PVC" + return hs + resourceExclusions: | + - apiGroups: + - project.openshift.io + clusters: + - '*' + kinds: + - Project + resourceIgnoreDifferences: + resourceIdentifiers: + - group: route.openshift.io + kind: Route + customization: + jsonPointers: + - /status/ingress + - group: quay.redhat.com + kind: QuayRegistry + customization: + jsonPointers: + - /status/ingress + ha: + enabled: false diff --git a/cluster-config/components/gitops-operator/base/kustomization.yaml b/cluster-config/components/gitops-operator/base/kustomization.yaml new file mode 100644 index 0000000..9dfe193 --- /dev/null +++ b/cluster-config/components/gitops-operator/base/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- setenv-cmp-plugin-cm.yaml +- argocd-external-secret.yaml +- create-pipeline-local-user-job.yaml +- gitops-operator-cr.yaml +- argocd-dex-server-rolebinding.yaml diff --git a/cluster-config/components/gitops-operator/base/setenv-cmp-plugin-cm.yaml b/cluster-config/components/gitops-operator/base/setenv-cmp-plugin-cm.yaml new file mode 100644 index 0000000..44e93f9 --- /dev/null +++ b/cluster-config/components/gitops-operator/base/setenv-cmp-plugin-cm.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: setenv-cmp-plugin +data: + plugin.yaml: | + apiVersion: argoproj.io/v1alpha1 + kind: ConfigManagementPlugin + metadata: + name: setenv-cmp-plugin + spec: + version: v1.0 + init: + command: [sh, -c, 'echo "Initializing setenv-plugin-cmp..."'] + generate: + command: [sh, -c, "set -o pipefail && kustomize build --enable-helm --enable-alpha-plugins . | perl -pe 's{\\$(\\{)?(\\w+)(?(1)\\})}{$ENV{$2} // $&}ge'"] + discover: + find: + command: [sh, -c, 'find . -maxdepth 1 -name kustomization.yaml'] diff --git a/cluster-config/components/gitops-operator/overlays/shared/README.md b/cluster-config/components/gitops-operator/overlays/shared/README.md new file mode 100644 index 0000000..d4c08a4 --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/README.md @@ -0,0 +1,2 @@ +This is a shared GitOps instance intended for tenants leveraging the new +Applications in Any Namespace feature GA in OpenShift GitOps 1.13 diff --git a/cluster-config/components/gitops-operator/overlays/shared/argocd-cluster-role.yaml b/cluster-config/components/gitops-operator/overlays/shared/argocd-cluster-role.yaml new file mode 100644 index 0000000..a3268d2 --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/argocd-cluster-role.yaml @@ -0,0 +1,184 @@ +# ClusterRole to aggregate permissions needed to use respectRBAC +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-shared-cluster-access +aggregationRule: + clusterRoleSelectors: + - matchLabels: + gitops/aggregate-to-gitops-shared: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-shared-cluster-access-view + labels: + gitops/aggregate-to-gitops-shared: "true" +# Use the aggrated view permission to determine what resources can be deployed. +# +# Note that write permissions for these resources in specific namespaces +# are determined by the cluster role granted via the "managed-by" label. +# You still need to grant the controller cluster level list permissions +# to pass the SubjectAccessReview. The view role gives get and watch as well +# so if you want to restrict permissions to just list you need to maintain +# your own hand-crafted list which turns out to be burdensome. +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.authorization.k8s.io/aggregate-to-view: "true" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-shared-cluster-access-base + labels: + gitops/aggregate-to-gitops-shared: "true" +rules: +# Base permissions the applicaton-controller needs for respectRBAC separate from resources +# grant read/write permissions so Argo CD UI and controllers can update status of resources. +- apiGroups: + - argoproj.io + resources: + - applications + - applicationsets + - appprojects + - rolloutmanagers + - rollouts + verbs: + - "*" +# SubjectAccessReview needed for respectRBAC=strict setting in Argo CD +- apiGroups: + - authorization.k8s.io + resources: + - selfsubjectaccessreviews + verbs: + - create +# Needs ability to list projects for some reason +- apiGroups: + - config.openshift.io + resources: + - "*" + verbs: + - get + - list + - watch +# Hand-crafted list of what we want to have Argo CD be able to use, turns +# out list becomes huge and hard to maintain so I have opted to just leverage +# the built-in view role. However if you want total control over permissions +# you can use these instead +# # Limited resource permissions here for tenants to deploy things +# - apiGroups: +# - "" +# resources: +# - configmaps +# - endpoints +# - persistentvolumeclaims +# - persistentvolumeclaims/status +# - pods +# - replicationcontrollers +# - replicationcontrollers/scale +# - serviceaccounts +# - services +# - services/status +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - "" +# resources: +# - bindings +# - events +# - limitranges +# - namespaces/status +# - pods/log +# - pods/status +# - replicationcontrollers/status +# - resourcequotas +# - resourcequotas/status +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - apps +# resources: +# - controllerrevisions +# - daemonsets +# - daemonsets/status +# - deployments +# - deployments/scale +# - deployments/status +# - replicasets +# - replicasets/scale +# - replicasets/status +# - statefulsets +# - statefulsets/scale +# - statefulsets/status +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - "" +# - route.openshift.io +# resources: +# - routes +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - "" +# - route.openshift.io +# resources: +# - routes/status +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - networking.k8s.io +# resources: +# - networkpolicies +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - rbac.authorization.k8s.io +# resources: +# - roles +# - rolebindings +# verbs: +# - get +# - list +# - watch +# - apiGroups: +# - monitoring.coreos.com +# resources: +# - servicemonitors +# verbs: +# - get +# - list +# - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: gitops-shared-cluster-access +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: gitops-shared-cluster-access +subjects: + - kind: ServiceAccount + name: argocd-argocd-application-controller + namespace: gitops + - kind: ServiceAccount + name: argocd-argocd-server + namespace: gitops + - kind: ServiceAccount + name: argocd-applicationset-controller + namespace: gitops diff --git a/cluster-config/components/gitops-operator/overlays/shared/argocd-notifications-cm.yaml b/cluster-config/components/gitops-operator/overlays/shared/argocd-notifications-cm.yaml new file mode 100644 index 0000000..4a04070 --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/argocd-notifications-cm.yaml @@ -0,0 +1,557 @@ +apiVersion: v1 +data: + template.app-created: |- + email: + subject: Application {{.app.metadata.name}} has been created. + message: Application {{.app.metadata.name}} has been created. + teams: + title: Application {{.app.metadata.name}} has been created. + template.app-deleted: |- + email: + subject: Application {{.app.metadata.name}} has been deleted. + message: Application {{.app.metadata.name}} has been deleted. + teams: + title: Application {{.app.metadata.name}} has been deleted. + template.app-deployed: |- + email: + subject: New version of an application {{.app.metadata.name}} is up and running. + message: | + {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} is now running new version of deployments manifests. + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + }, + { + "title": "Revision", + "value": "{{.app.status.sync.revision}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + }, + { + "name": "Revision", + "value": "{{.app.status.sync.revision}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Operation Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#000080' + title: New version of an application {{.app.metadata.name}} is up and running. + template.app-health-degraded: |- + email: + subject: Application {{.app.metadata.name}} has degraded. + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded. + Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#f4c030", + "fields": [ + { + "title": "Health Status", + "value": "{{.app.status.health.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Health Status", + "value": "{{.app.status.health.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: | + [{ + "@type":"OpenUri", + "name":"Open Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#FF0000' + title: Application {{.app.metadata.name}} has degraded. + template.app-sync-failed: |- + email: + subject: Failed to sync application {{.app.metadata.name}}. + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} The sync operation of application {{.app.metadata.name}} has failed at {{.app.status.operationState.finishedAt}} with the following error: {{.app.status.operationState.message}} + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Failed at", + "value": "{{.app.status.operationState.finishedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Operation", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#FF0000' + title: Failed to sync application {{.app.metadata.name}}. + template.app-sync-running: |- + email: + subject: Start syncing application {{.app.metadata.name}}. + message: | + The sync operation of application {{.app.metadata.name}} has started at {{.app.status.operationState.startedAt}}. + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#0DADEA", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Started at", + "value": "{{.app.status.operationState.startedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Operation", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + title: Start syncing application {{.app.metadata.name}}. + template.app-sync-status-unknown: |- + email: + subject: Application {{.app.metadata.name}} sync status is 'Unknown' + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} sync is 'Unknown'. + Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. + {{if ne .serviceType "slack"}} + {{range $c := .app.status.conditions}} + * {{$c.message}} + {{end}} + {{end}} + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + title: Application {{.app.metadata.name}} sync status is 'Unknown' + template.app-sync-succeeded: |- + email: + subject: Application {{.app.metadata.name}} has been successfully synced. + message: | + {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}. + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Synced at", + "value": "{{.app.status.operationState.finishedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Operation Details", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#000080' + title: Application {{.app.metadata.name}} has been successfully synced + trigger.on-created: |- + - description: Application is created. + oncePer: app.metadata.name + send: + - app-created + when: "true" + trigger.on-deleted: |- + - description: Application is deleted. + oncePer: app.metadata.name + send: + - app-deleted + when: app.metadata.deletionTimestamp != nil + trigger.on-deployed: |- + - description: Application is synced and healthy. Triggered once per commit. + oncePer: app.status.operationState.syncResult.revision + send: + - app-deployed + when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status + == 'Healthy' + trigger.on-health-degraded: |- + - description: Application has degraded + send: + - app-health-degraded + when: app.status.health.status == 'Degraded' + trigger.on-sync-failed: |- + - description: Application syncing has failed + send: + - app-sync-failed + when: app.status.operationState.phase in ['Error', 'Failed'] + trigger.on-sync-running: |- + - description: Application is being synced + send: + - app-sync-running + when: app.status.operationState.phase in ['Running'] + trigger.on-sync-status-unknown: |- + - description: Application status is 'Unknown' + end: + - app-sync-status-unknown + when: app.status.sync.status == 'Unknown' + trigger.on-sync-succeeded: |- + - description: Application syncing has succeeded + send: + - app-sync-succeeded + - server-post-prod-app-sync + when: app.status.operationState.phase in ['Succeeded'] + # Tekton Webhook Definitions + service.webhook.server-post-prod: |- + url: http://el-server-post-prod.product-catalog-cicd.svc:8080 + template.server-post-prod-app-sync: |- + webhook: + server-post-prod: + method: POST + path: / + body: | + { + {{if eq .app.status.operationState.phase "Running"}} "state": "pending"{{end}} + {{if eq .app.status.operationState.phase "Succeeded"}} "state": "success"{{end}} + {{if eq .app.status.operationState.phase "Error"}} "state": "error"{{end}} + {{if eq .app.status.operationState.phase "Failed"}} "state": "error"{{end}}, + "description": "ArgoCD", + "application": "{{.app.metadata.name}}" + } +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/managed-by: argocd + app.kubernetes.io/name: argocd-notifications-cm + app.kubernetes.io/part-of: argocd + name: argocd-notifications-cm + namespace: product-catalog-gitops diff --git a/cluster-config/components/gitops-operator/overlays/shared/console-link.yaml b/cluster-config/components/gitops-operator/overlays/shared/console-link.yaml new file mode 100644 index 0000000..42d088d --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/console-link.yaml @@ -0,0 +1,12 @@ +apiVersion: console.openshift.io/v1 +kind: ConsoleLink +metadata: + name: shared-gitops +spec: + applicationMenu: + imageURL: data:image/png;base64,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 + section: OpenShift GitOps + href: 'https://argocd-server-gitops.${SUB_DOMAIN}' + location: ApplicationMenu + # This text will appear in a box called "Launcher" under "namespace" or "project" in the web console + text: Shared Argo CD diff --git a/cluster-config/components/gitops-operator/overlays/shared/gitops-monitoring-cluster-role.yaml b/cluster-config/components/gitops-operator/overlays/shared/gitops-monitoring-cluster-role.yaml new file mode 100644 index 0000000..d1fe635 --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/gitops-monitoring-cluster-role.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gitops-monitoring-cluster-role + labels: + gitops/aggregate-to-controller: "true" +rules: +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + - podmonitors + verbs: + - '*' diff --git a/cluster-config/components/gitops-operator/overlays/shared/global-appproject.yaml b/cluster-config/components/gitops-operator/overlays/shared/global-appproject.yaml new file mode 100644 index 0000000..d75ae8f --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/global-appproject.yaml @@ -0,0 +1,28 @@ +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: global +spec: + description: Global Configuration + clusterResourceBlacklist: + - group: '*' + kind: '*' + namespaceResourceBlacklist: + - group: '' + kind: Namespace + - group: '' + kind: ResourceQuota + - group: '' + kind: LimitRange + - group: operators.coreos.com + kind: '*' + - group: operator.openshift.io + kind: '*' + - group: storage.k8s.io + kind: '*' + - group: machine.openshift.io + kind: '*' + - group: machineconfiguration.openshift.io + kind: '*' + - group: compliance.openshift.io + kind: '*' diff --git a/cluster-config/components/gitops-operator/overlays/shared/kustomization.yaml b/cluster-config/components/gitops-operator/overlays/shared/kustomization.yaml new file mode 100644 index 0000000..ba3812e --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/kustomization.yaml @@ -0,0 +1,73 @@ +namespace: gitops + +resources: + - ../../base + - argocd-cluster-role.yaml + - gitops-monitoring-cluster-role.yaml + - namespace.yaml + - argocd-notifications-cm.yaml + - console-link.yaml + - global-appproject.yaml + - prometheus-rules.yaml + +patches: + # Update permissions for tenants and local accounts, note ACCOUNT_NAMESPACES is space separated + - patch: |- + - op: replace + path: /spec/template/spec/containers/0/env + value: + - name: ACCOUNTS_NAMESPACES + value: "product-catalog-pipeline=product-catalog-cicd rollouts-demo-pipeline=rollouts-demo-cicd" + - name: ARGO_SERVER_HOST + value: "argocd-server-gitops.${SUB_DOMAIN}" + target: + kind: Job + name: create-pipeline-local-user + - target: + kind: ArgoCD + name: argocd + patch: |- + - op: add + path: /spec/defaultClusterScopedRoleDisabled + value: true + - op: add + path: /spec/extraConfig + value: + resource.respectRBAC: "strict" + exec.enabled: "true" + globalProjects: |- + - labelSelector: + matchExpressions: + - key: argocd.argoproj.io/project-inherit + operator: In + values: + - global + projectName: global + accounts.product-catalog-pipeline: apiKey + accounts.rollouts-demo-pipeline: apiKey + oidc.config: | + name: Keycloak + issuer: https://sso.ocplab.com/realms/ocplab + clientID: argocd + clientSecret: $oidc.keycloak.clientSecret + requestedScopes: ["openid", "profile", "email", "groups"] + - op: add + path: /spec/sourceNamespaces + value: + - product-catalog-gitops + - rollouts-demo-gitops + - op: add + path: /spec/rbac + value: + defaultPolicy: 'role:none' + policy: | + p, role:none, *, *, */*, deny + g, system:cluster-admins, role:admin + g, cluster-admins, role:admin + p, role:developers, clusters, get, *, allow + p, role:developers, repositories, get, *, allow + g, developers, role:developers + scopes: "[accounts,groups]" + - op: add + path: /spec/server/host + value: "argocd-server-gitops.${SUB_DOMAIN}" diff --git a/cluster-config/components/gitops-operator/overlays/shared/namespace.yaml b/cluster-config/components/gitops-operator/overlays/shared/namespace.yaml new file mode 100644 index 0000000..9ee04b4 --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/description: Project for tenants GitOps Operator instance + openshift.io/display-name: GitOps + name: gitops diff --git a/cluster-config/components/gitops-operator/overlays/shared/prometheus-rules.yaml b/cluster-config/components/gitops-operator/overlays/shared/prometheus-rules.yaml new file mode 100644 index 0000000..243c694 --- /dev/null +++ b/cluster-config/components/gitops-operator/overlays/shared/prometheus-rules.yaml @@ -0,0 +1,35 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: argocd-unhealthy-alert + annotations: + policy.open-cluster-management.io/disable-templates: "true" +spec: + groups: + - name: ArgoCD + rules: + - alert: ArgoCDHealthAlert + annotations: + message: ArgoCD application {{ $labels.name }} is not healthy + expr: argocd_app_info{namespace="openshift-gitops", health_status!~"Healthy|Suspended|Progressing|Degraded"} > 0 + for: 5m + labels: + severity: warning +--- +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: argocd-degraded-alert + annotations: + policy.open-cluster-management.io/disable-templates: "true" +spec: + groups: + - name: ArgoCD + rules: + - alert: ArgoCDDegradedAlert + annotations: + message: ArgoCD application {{ $labels.name }} is degraded + expr: argocd_app_info{namespace="openshift-gitops", health_status="Degraded"} > 0 + for: 5m + labels: + severity: critical diff --git a/cluster-config/components/helm-repos/base/gnunn-gitops-repo.yaml b/cluster-config/components/helm-repos/base/gnunn-gitops-repo.yaml new file mode 100644 index 0000000..7e476db --- /dev/null +++ b/cluster-config/components/helm-repos/base/gnunn-gitops-repo.yaml @@ -0,0 +1,8 @@ +apiVersion: helm.openshift.io/v1beta1 +kind: HelmChartRepository +metadata: + name: demo-helm-charts +spec: + connectionConfig: + url: 'https://gnunn-gitops.github.io/helm-charts' + name: Demo Helm Charts diff --git a/cluster-config/components/helm-repos/base/kustomization.yaml b/cluster-config/components/helm-repos/base/kustomization.yaml new file mode 100644 index 0000000..bd4b5c6 --- /dev/null +++ b/cluster-config/components/helm-repos/base/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- gnunn-gitops-repo.yaml diff --git a/cluster-config/components/kyverno-acm/base/generate/.skip_validation b/cluster-config/components/kyverno-acm/base/generate/.skip_validation new file mode 100644 index 0000000..e69de29 diff --git a/cluster-config/components/kyverno-acm/base/generate/best-practices-policyGenerator.yaml b/cluster-config/components/kyverno-acm/base/generate/best-practices-policyGenerator.yaml new file mode 100644 index 0000000..0d218d5 --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/generate/best-practices-policyGenerator.yaml @@ -0,0 +1,90 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: kyverno-bestpractices +placementBindingDefaults: + name: kyverno-bestpractices +policyDefaults: + policyAnnotations: {"policy.open-cluster-management.io/disable-templates": "true"} + categories: + - CM Configuration Management + controls: + - CM-2 Baseline Configuration + namespace: kyverno-policies + remediationAction: enforce + severity: medium + policySets: + - kyverno-best-practices + standards: + - generic + generatePlacementWhenInSet: false +policies: +- name: policy-require-pod-probes + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/validate-probes-policy.yaml +- name: require-requests-limits + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/require-requests-limits-policy.yaml +- name: application-field-validation + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/application-field-validation.yaml +- name: application-prevent-default-project + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/application-prevent-default-project.yaml +- name: check-deprecated-apis + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/check-deprecated-apis.yaml +- name: check-openshift-deprecated-apis + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/check-openshift-deprecated-apis.yaml +- name: disallow-jenkins-pipeline-strategy + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/disallow-jenkins-pipeline-strategy.yaml +- name: disallow-latest-tag + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/disallow-latest-tag.yaml +policySets: + - description: Kyverno Best Practices + name: kyverno-best-practices + placement: + placementRuleName: kyverno diff --git a/cluster-config/components/kyverno-acm/base/generate/generate.sh b/cluster-config/components/kyverno-acm/base/generate/generate.sh new file mode 100755 index 0000000..f36c8c4 --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/generate/generate.sh @@ -0,0 +1,3 @@ +cp -R ../../../kyverno/overlays/policies policies +kustomize --enable-helm --enable-alpha-plugins build . > ../kyverno-acm-policies.yaml +rm -rf policies diff --git a/cluster-config/components/kyverno-acm/base/generate/kustomization.yaml b/cluster-config/components/kyverno-acm/base/generate/kustomization.yaml new file mode 100644 index 0000000..e48514e --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/generate/kustomization.yaml @@ -0,0 +1,17 @@ +generators: +- best-practices-policyGenerator.yaml +- security-policyGenerator.yaml + +patches: + - target: + kind: ClusterPolicy + patch: |- + - op: replace + path: /spec/validationFailureAction + value: enforce + # Using Argo to deliver policies so just keep reporting on PolicyReports + - target: + kind: Policy + patch: |- + - op: remove + path: /spec/policy-templates/0 diff --git a/cluster-config/components/kyverno-acm/base/generate/security-policyGenerator.yaml b/cluster-config/components/kyverno-acm/base/generate/security-policyGenerator.yaml new file mode 100644 index 0000000..bc357b2 --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/generate/security-policyGenerator.yaml @@ -0,0 +1,42 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PolicyGenerator +metadata: + name: kyverno-security +placementBindingDefaults: + name: kyverno-security +policyDefaults: + policyAnnotations: {"policy.open-cluster-management.io/disable-templates": "true"} + categories: + - CM Configuration Management + controls: + - CM-2 Baseline Configuration + namespace: kyverno-policies + remediationAction: enforce + severity: medium + policySets: + - kyverno-security + standards: + - generic + generatePlacementWhenInSet: false +policies: +- name: disallow-scc-anyuid + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/disallow-anyuid-scc-policy.yaml +- name: require-tls-routes + categories: + - setup + controls: + - setup + disabled: false + manifests: + - path: policies/require-tls-routes.yaml +policySets: + - description: Kyverno Security + name: kyverno-security + placement: + placementRuleName: kyverno diff --git a/cluster-config/components/kyverno-acm/base/kustomization.yaml b/cluster-config/components/kyverno-acm/base/kustomization.yaml new file mode 100644 index 0000000..83025c2 --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/kustomization.yaml @@ -0,0 +1,8 @@ +namespace: acm-policies + +commonAnnotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + +resources: +- placementrule.yaml +- kyverno-acm-policies.yaml diff --git a/cluster-config/components/kyverno-acm/base/kyverno-acm-policies.yaml b/cluster-config/components/kyverno-acm/base/kyverno-acm-policies.yaml new file mode 100644 index 0000000..f1ad517 --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/kyverno-acm-policies.yaml @@ -0,0 +1,475 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: kyverno-bestpractices + namespace: kyverno-policies +placementRef: + apiGroup: apps.open-cluster-management.io + kind: PlacementRule + name: kyverno +subjects: +- apiGroup: policy.open-cluster-management.io + kind: PolicySet + name: kyverno-best-practices +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: kyverno-security + namespace: kyverno-policies +placementRef: + apiGroup: apps.open-cluster-management.io + kind: PlacementRule + name: kyverno +subjects: +- apiGroup: policy.open-cluster-management.io + kind: PolicySet + name: kyverno-security +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: application-field-validation + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-application-field-validation + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: application-field-validation + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: application-field-validation + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: application-prevent-default-project + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-application-prevent-default-project + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: application-prevent-default-project + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: application-prevent-default-project + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: check-deprecated-apis + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-check-deprecated-apis + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: check-deprecated-apis + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: check-deprecated-apis + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: check-openshift-deprecated-apis + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-check-openshift-deprecated-apis + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: check-openshift-deprecated-apis + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: check-openshift-deprecated-apis + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: disallow-jenkins-pipeline-strategy + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-disallow-jenkins-pipeline-strategy + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: disallow-jenkins-pipeline-strategy + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: disallow-jenkins-pipeline-strategy + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: disallow-latest-tag + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-disallow-latest-tag + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: disallow-latest-tag + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: disallow-latest-tag + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: disallow-scc-anyuid + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-disallow-security-context-constraint-anyuid + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: disallow-security-context-constraint-anyuid + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: disallow-security-context-constraint-anyuid + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: policy-require-pod-probes + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-require-pod-probes + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: require-pod-probes + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: require-pod-probes + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: require-requests-limits + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-require-requests-limits + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: require-requests-limits + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: require-requests-limits + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + annotations: + policy.open-cluster-management.io/categories: setup + policy.open-cluster-management.io/controls: setup + policy.open-cluster-management.io/disable-templates: "true" + policy.open-cluster-management.io/standards: generic + name: require-tls-routes + namespace: kyverno-policies +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: inform-kyverno-check-routes + spec: + namespaceSelector: + exclude: + - kube-* + include: + - '*' + object-templates: + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: ClusterPolicyReport + results: + - policy: check-routes + result: fail + - complianceType: mustnothave + objectDefinition: + apiVersion: wgpolicyk8s.io/v1alpha2 + kind: PolicyReport + results: + - policy: check-routes + result: fail + remediationAction: inform + severity: medium +--- +apiVersion: policy.open-cluster-management.io/v1beta1 +kind: PolicySet +metadata: + name: kyverno-best-practices + namespace: kyverno-policies +spec: + description: Kyverno Best Practices + policies: + - application-field-validation + - application-prevent-default-project + - check-deprecated-apis + - check-openshift-deprecated-apis + - disallow-jenkins-pipeline-strategy + - disallow-latest-tag + - policy-require-pod-probes + - require-requests-limits +--- +apiVersion: policy.open-cluster-management.io/v1beta1 +kind: PolicySet +metadata: + name: kyverno-security + namespace: kyverno-policies +spec: + description: Kyverno Security + policies: + - disallow-scc-anyuid + - require-tls-routes diff --git a/cluster-config/components/kyverno-acm/base/placementrule.yaml b/cluster-config/components/kyverno-acm/base/placementrule.yaml new file mode 100644 index 0000000..8d13fa3 --- /dev/null +++ b/cluster-config/components/kyverno-acm/base/placementrule.yaml @@ -0,0 +1,14 @@ +apiVersion: apps.open-cluster-management.io/v1 +kind: PlacementRule +metadata: + name: kyverno +spec: + clusterConditions: + - status: "True" + type: ManagedClusterConditionAvailable + clusterSelector: + matchExpressions: + - key: policies + operator: In + values: + - kyverno diff --git a/cluster-config/components/kyverno/base/kustomization.yaml b/cluster-config/components/kyverno/base/kustomization.yaml new file mode 100644 index 0000000..b3b445f --- /dev/null +++ b/cluster-config/components/kyverno/base/kustomization.yaml @@ -0,0 +1,23 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- namespace.yaml + +helmCharts: +- name: kyverno + version: 3.0.5 + repo: https://kyverno.github.io/kyverno/ + valuesFile: values.yaml + namespace: kyverno + releaseName: kyverno + +# Delete kyverno PDB, not useful on SNO +patches: + - patch: |- + $patch: delete + apiVersion: policy/v1 + kind: PodDisruptionBudget + metadata: + name: kyverno-admission-controller + namespace: kyverno diff --git a/cluster-config/components/kyverno/base/namespace.yaml b/cluster-config/components/kyverno/base/namespace.yaml new file mode 100644 index 0000000..3d79b42 --- /dev/null +++ b/cluster-config/components/kyverno/base/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/description: Kyverno Policy Engine + openshift.io/display-name: Kyverno + name: kyverno diff --git a/cluster-config/components/kyverno/base/values.yaml b/cluster-config/components/kyverno/base/values.yaml new file mode 100644 index 0000000..5772ba7 --- /dev/null +++ b/cluster-config/components/kyverno/base/values.yaml @@ -0,0 +1,269 @@ +admissionController: + replicas: 3 + antiAffinity: + # anti-affinity won't work on SNO + enabled: false + resources: + limits: + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + +backgroundController: + replicas: 1 + antiAffinity: + # anti-affinity won't work on SNO + enabled: false + +cleanupController: + replicas: 1 + antiAffinity: + # anti-affinity won't work on SNO + enabled: false + resources: + limits: + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + +reportsController: + replicas: 1 + antiAffinity: + # anti-affinity won't work on SNO + enabled: false + resources: + limits: + memory: 256Mi + cpu: 4000m + requests: + cpu: 100m + memory: 128Mi + +crds: + install: true + annotations: + argocd.argoproj.io/sync-options: Validate=false,ServerSideApply=true + +apiVersionOverride: + podDisruptionBudget: policy/v1 + +config: + resourceFilters: + - '[Event,*,*]' + - '[*/*,default,*]' + - '[*/*,kube-system,*]' + - '[*/*,kube-public,*]' + - '[*/*,kube-node-lease,*]' + - '[*/*,openshift,*]' + - '[*/*, openshift-*, *]' + - '[*/*,open-cluster-*,*]' + - '[*/*,hive,*]' + - '[*/*, multicluster-engine,*]' + - '[*/*,stackrox,*]' + - '[*/*,rhacs-operator,*]' + - '[*/*,costmanagement-metrics-operator,*]' + - '[Node,*,*]' + - '[Node/*,*,*]' + - '[APIService,*,*]' + - '[APIService/*,*,*]' + - '[TokenReview,*,*]' + - '[SubjectAccessReview,*,*]' + - '[SelfSubjectAccessReview,*,*]' + - '[Binding,*,*]' + - '[Pod/binding,*,*]' + - '[ReplicaSet,*,*]' + - '[ReplicaSet/*,*,*]' + - '[AdmissionReport,*,*]' + - '[AdmissionReport/*,*,*]' + - '[ClusterAdmissionReport,*,*]' + - '[ClusterAdmissionReport/*,*,*]' + - '[BackgroundScanReport,*,*]' + - '[BackgroundScanReport/*,*,*]' + - '[ClusterBackgroundScanReport,*,*]' + - '[ClusterBackgroundScanReport/*,*,*]' + # exclude resources from the chart + - '[ClusterRole,*,{{ template "kyverno.admission-controller.roleName" . }}]' + - '[ClusterRole,*,{{ template "kyverno.admission-controller.roleName" . }}:core]' + - '[ClusterRole,*,{{ template "kyverno.admission-controller.roleName" . }}:additional]' + - '[ClusterRole,*,{{ template "kyverno.background-controller.roleName" . }}]' + - '[ClusterRole,*,{{ template "kyverno.background-controller.roleName" . }}:core]' + - '[ClusterRole,*,{{ template "kyverno.background-controller.roleName" . }}:additional]' + - '[ClusterRole,*,{{ template "kyverno.cleanup-controller.roleName" . }}]' + - '[ClusterRole,*,{{ template "kyverno.cleanup-controller.roleName" . }}:core]' + - '[ClusterRole,*,{{ template "kyverno.cleanup-controller.roleName" . }}:additional]' + - '[ClusterRole,*,{{ template "kyverno.reports-controller.roleName" . }}]' + - '[ClusterRole,*,{{ template "kyverno.reports-controller.roleName" . }}:core]' + - '[ClusterRole,*,{{ template "kyverno.reports-controller.roleName" . }}:additional]' + - '[ClusterRoleBinding,*,{{ template "kyverno.admission-controller.roleName" . }}]' + - '[ClusterRoleBinding,*,{{ template "kyverno.background-controller.roleName" . }}]' + - '[ClusterRoleBinding,*,{{ template "kyverno.cleanup-controller.roleName" . }}]' + - '[ClusterRoleBinding,*,{{ template "kyverno.reports-controller.roleName" . }}]' + - '[ServiceAccount,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceAccountName" . }}]' + - '[ServiceAccount/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceAccountName" . }}]' + - '[ServiceAccount,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.serviceAccountName" . }}]' + - '[ServiceAccount/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.serviceAccountName" . }}]' + - '[ServiceAccount,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.serviceAccountName" . }}]' + - '[ServiceAccount/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.serviceAccountName" . }}]' + - '[ServiceAccount,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.serviceAccountName" . }}]' + - '[ServiceAccount/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.serviceAccountName" . }}]' + - '[Role,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.roleName" . }}]' + - '[Role,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.roleName" . }}]' + - '[Role,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.roleName" . }}]' + - '[Role,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.roleName" . }}]' + - '[RoleBinding,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.roleName" . }}]' + - '[RoleBinding,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.roleName" . }}]' + - '[RoleBinding,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.roleName" . }}]' + - '[RoleBinding,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.roleName" . }}]' + - '[ConfigMap,{{ include "kyverno.namespace" . }},{{ template "kyverno.config.configMapName" . }}]' + - '[ConfigMap,{{ include "kyverno.namespace" . }},{{ template "kyverno.config.metricsConfigMapName" . }}]' + - '[Deployment,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}]' + - '[Deployment/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}]' + - '[Deployment,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}]' + - '[Deployment/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}]' + - '[Deployment,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[Deployment/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[Deployment,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}]' + - '[Deployment/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}]' + - '[Pod,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}-*]' + - '[Pod/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}-*]' + - '[Pod,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}-*]' + - '[Pod/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}-*]' + - '[Pod,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}-*]' + - '[Pod/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}-*]' + - '[Pod,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}-*]' + - '[Pod/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}-*]' + - '[Job,{{ include "kyverno.namespace" . }},{{ template "kyverno.fullname" . }}-hook-pre-delete]' + - '[Job/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.fullname" . }}-hook-pre-delete]' + - '[NetworkPolicy,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}]' + - '[NetworkPolicy/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}]' + - '[NetworkPolicy,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}]' + - '[NetworkPolicy/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}]' + - '[NetworkPolicy,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[NetworkPolicy/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[NetworkPolicy,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}]' + - '[NetworkPolicy/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}]' + - '[PodDisruptionBudget,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}]' + - '[PodDisruptionBudget/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.name" . }}]' + - '[PodDisruptionBudget,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}]' + - '[PodDisruptionBudget/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}]' + - '[PodDisruptionBudget,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[PodDisruptionBudget/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[PodDisruptionBudget,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}]' + - '[PodDisruptionBudget/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}]' + - '[Service,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceName" . }}]' + - '[Service/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceName" . }}]' + - '[Service,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceName" . }}-metrics]' + - '[Service/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceName" . }}-metrics]' + - '[Service,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}-metrics]' + - '[Service/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.background-controller.name" . }}-metrics]' + - '[Service,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[Service/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[Service,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}-metrics]' + - '[Service/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}-metrics]' + - '[Service,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}-metrics]' + - '[Service/*,{{ include "kyverno.namespace" . }},{{ template "kyverno.reports-controller.name" . }}-metrics]' + - '[ServiceMonitor,{{ if .Values.admissionController.serviceMonitor.namespace }}{{ .Values.admissionController.serviceMonitor.namespace }}{{ else }}{{ template "kyverno.namespace" . }}{{ end }},{{ template "kyverno.admission-controller.name" . }}]' + - '[ServiceMonitor,{{ if .Values.admissionController.serviceMonitor.namespace }}{{ .Values.admissionController.serviceMonitor.namespace }}{{ else }}{{ template "kyverno.namespace" . }}{{ end }},{{ template "kyverno.background-controller.name" . }}]' + - '[ServiceMonitor,{{ if .Values.admissionController.serviceMonitor.namespace }}{{ .Values.admissionController.serviceMonitor.namespace }}{{ else }}{{ template "kyverno.namespace" . }}{{ end }},{{ template "kyverno.cleanup-controller.name" . }}]' + - '[ServiceMonitor,{{ if .Values.admissionController.serviceMonitor.namespace }}{{ .Values.admissionController.serviceMonitor.namespace }}{{ else }}{{ template "kyverno.namespace" . }}{{ end }},{{ template "kyverno.reports-controller.name" . }}]' + - '[Secret,{{ include "kyverno.namespace" . }},{{ template "kyverno.admission-controller.serviceName" . }}.{{ template "kyverno.namespace" . }}.svc.*]' + - '[Secret,{{ include "kyverno.namespace" . }},{{ template "kyverno.cleanup-controller.name" . }}.{{ template "kyverno.namespace" . }}.svc.*]' + + webhooks: + # Exclude namespaces + - namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + # System namespaces + - default + - kyverno + - kube-system + - kube-node-lease + # OpenShift layered products + - assisted-installer + - cert-manager + - cert-manager-operator + - stackrox + - stackrox-secured-cluster-service + - rhacs-operator + - multicluster-engine + - open-cluster-management + - open-cluster-management-hub + - open-cluster-management-observability + - open-cluster-management-addon-observability + - open-cluster-management-agent + - open-cluster-management-agent-addon + - open-cluster-management-global-set + # Third Party + - external-secrets + # OpenShift namespaces + - openshift + - openshift-apiserver + - openshift-apiserver-operator + - openshift-authentication + - openshift-authentication-operator + - openshift-cloud-controller-manager + - openshift-cloud-controller-manager-operator + - openshift-cloud-credential-operator + - openshift-cloud-network-config-controller + - openshift-cluster-csi-drivers + - openshift-cluster-machine-approver + - openshift-cluster-node-tuning-operator + - openshift-cluster-samples-operator + - openshift-cluster-storage-operator + - openshift-cluster-version + - openshift-config + - openshift-config-managed + - openshift-config-operator + - openshift-console + - openshift-console-operator + - openshift-console-user-settings + - openshift-controller-manager + - openshift-controller-manager-operator + - openshift-dns + - openshift-dns-operator + - openshift-etcd + - openshift-etcd-operator + - openshift-gitops + - openshift-host-network + - openshift-image-registry + - openshift-infra + - openshift-ingress + - openshift-ingress-canary + - openshift-ingress-operator + - openshift-insights + - openshift-kni-infra + - openshift-kube-apiserver + - openshift-kube-apiserver-operator + - openshift-kube-controller-manager + - openshift-kube-controller-manager-operator + - openshift-kube-scheduler + - openshift-kube-scheduler-operator + - openshift-kube-storage-version-migrator + - openshift-kube-storage-version-migrator-operator + - openshift-machine-api + - openshift-machine-config-operator + - openshift-marketplace + - openshift-monitoring + - openshift-multus + - openshift-network-diagnostics + - openshift-network-operator + - openshift-node + - openshift-nutanix-infra + - openshift-oauth-apiserver + - openshift-openstack-infra + - openshift-operator-lifecycle-manager + - openshift-operators + - openshift-ovirt-infra + - openshift-ovn-kubernetes + - openshift-pipelines + - openshift-route-controller-manager + - openshift-service-ca + - openshift-service-ca-operator + - openshift-storage + - openshift-user-workload-monitoring + - openshift-vsphere-infra diff --git a/cluster-config/components/kyverno/overlays/policies/annotate-route-argo-external-link.yaml b/cluster-config/components/kyverno/overlays/policies/annotate-route-argo-external-link.yaml new file mode 100644 index 0000000..bc98222 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/annotate-route-argo-external-link.yaml @@ -0,0 +1,64 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: annotate-argo-cd-external-link + annotations: + policies.kyverno.io/title: Annotate Route with Argo CD External Link + policies.kyverno.io/category: Argo + policies.kyverno.io/minversion: 1.0.0 + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Route + policies.kyverno.io/description: >- + This policy adds an annotation to a route that will cause the Argo CD UI + to display an icon representing a clickable link for the route. +spec: + validationFailureAction: audit + rules: + - name: add-annotations-for-https + match: + any: + - resources: + kinds: + - route.openshift.io/v1/Route + operations: + - UPDATE + preconditions: + all: + - key: "{{ request.object.spec.host || '' }}" + operator: NotEquals + value: "" + - key: "{{ request.object.metadata.annotations.\"argocd.argoproj.io/tracking-id\" || '' }}" + operator: NotEquals + value: "" + - key: "{{ request.object.spec.tls.termination || '' }}" + operator: NotEquals + value: "" + mutate: + patchStrategicMerge: + metadata: + annotations: + +(link.argocd.argoproj.io/external-link): https://{{ request.object.spec.host }}/{{ request.object.spec.path || '' }} + - name: add-annotations-for-http + match: + any: + - resources: + kinds: + - route.openshift.io/v1/Route + operations: + - UPDATE + preconditions: + all: + - key: "{{ request.object.spec.host || '' }}" + operator: NotEquals + value: "" + - key: "{{ request.object.metadata.annotations.\"argocd.argoproj.io/tracking-id\" || '' }}" + operator: NotEquals + value: "" + - key: "{{ request.object.spec.tls.termination || '' }}" + operator: Equals + value: "" + mutate: + patchStrategicMerge: + metadata: + annotations: + +(link.argocd.argoproj.io/external-link): http://{{ request.object.spec.host }}/{{ request.object.spec.path || '' }} diff --git a/cluster-config/components/kyverno/overlays/policies/application-field-validation.yaml b/cluster-config/components/kyverno/overlays/policies/application-field-validation.yaml new file mode 100644 index 0000000..10f817b --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/application-field-validation.yaml @@ -0,0 +1,57 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: application-field-validation + annotations: + policies.kyverno.io/title: Application Field Validation + policies.kyverno.io/category: Argo + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Application + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.23" + policies.kyverno.io/description: >- + This policy performs some best practices validation on Application fields. + Path or chart must be specified but never both. And destination.name or + destination.server must be specified but never both. +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: source-path-chart + match: + any: + - resources: + kinds: + - Application + validate: + message: >- + `spec.source.path` OR `spec.source.chart` should be specified but never both. + anyPattern: + - spec: + source: + path: '?*' + X(chart): + - spec: + source: + X(path): + chart: '?*' + - name: destination-server-name + match: + any: + - resources: + kinds: + - Application + validate: + message: >- + `spec.destination.server` OR `spec.destination.name` should be specified but never both. + anyPattern: + - spec: + destination: + server: '?*' + X(name): + - spec: + destination: + X(server): + name: '?*' diff --git a/cluster-config/components/kyverno/overlays/policies/application-prevent-default-project.yaml b/cluster-config/components/kyverno/overlays/policies/application-prevent-default-project.yaml new file mode 100644 index 0000000..51149c5 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/application-prevent-default-project.yaml @@ -0,0 +1,35 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: application-prevent-default-project + annotations: + policies.kyverno.io/title: Prevent Use of Default Project + policies.kyverno.io/category: Argo + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.6.2 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.23" + policies.kyverno.io/subject: Application + policies.kyverno.io/description: >- + This policy prevents the use of the default project in an Application. +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: default-project + match: + any: + - resources: + kinds: + - Application + preconditions: + all: + - key: "{{ request.operation }}" + operator: NotEquals + value: DELETE + validate: + message: "The default project may not be used in an Application." + pattern: + spec: + project: "!default" diff --git a/cluster-config/components/kyverno/overlays/policies/check-deprecated-apis.yaml b/cluster-config/components/kyverno/overlays/policies/check-deprecated-apis.yaml new file mode 100644 index 0000000..10e6625 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/check-deprecated-apis.yaml @@ -0,0 +1,119 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-deprecated-apis + annotations: + policies.kyverno.io/title: Check deprecated APIs + policies.kyverno.io/category: Best Practices + policies.kyverno.io/subject: Kubernetes APIs + kyverno.io/kyverno-version: 1.7.4 + policies.kyverno.io/minversion: 1.7.4 + kyverno.io/kubernetes-version: "1.23" + policies.kyverno.io/description: >- + Kubernetes APIs are sometimes deprecated and removed after a few releases. + As a best practice, older API versions should be replaced with newer versions. + This policy validates for APIs that are deprecated or scheduled for removal. + Note that checking for some of these resources may require modifying the Kyverno + ConfigMap to remove filters. In the validate-v1-22-removals rule, the Lease kind + has been commented out due to a check for this kind having a performance penalty + on Kubernetes clusters with many leases. Its enabling should be attended carefully + and is not recommended on large clusters. PodSecurityPolicy is removed in v1.25 + so therefore the validate-v1-25-removals rule may not completely work on 1.25+. + This policy requires Kyverno v1.7.4+ to function properly. +spec: + validationFailureAction: audit + background: true + rules: + - name: validate-v1-25-removals + match: + any: + - resources: + # NOTE: PodSecurityPolicy is completely removed in 1.25. + kinds: + - batch/*/CronJob + - discovery.k8s.io/*/EndpointSlice + - events.k8s.io/*/Event + - policy/*/PodDisruptionBudget + - node.k8s.io/*/RuntimeClass + preconditions: + all: + - key: "{{ request.operation || 'BACKGROUND' }}" + operator: NotEquals + value: DELETE + - key: "{{request.object.apiVersion}}" + operator: AnyIn + value: + - batch/v1beta1 + - discovery.k8s.io/v1beta1 + - events.k8s.io/v1beta1 + - policy/v1beta1 + - node.k8s.io/v1beta1 + validate: + message: >- + {{ request.object.apiVersion }}/{{ request.object.kind }} is deprecated and will be removed in v1.25. + See: https://kubernetes.io/docs/reference/using-api/deprecation-guide/ + deny: {} + - name: validate-v1-26-removals + match: + any: + - resources: + kinds: + - flowcontrol.apiserver.k8s.io/*/FlowSchema + - flowcontrol.apiserver.k8s.io/*/PriorityLevelConfiguration + - autoscaling/*/HorizontalPodAutoscaler + preconditions: + all: + - key: "{{ request.operation || 'BACKGROUND' }}" + operator: NotEquals + value: DELETE + - key: "{{request.object.apiVersion}}" + operator: AnyIn + value: + - flowcontrol.apiserver.k8s.io/v1beta1 + - autoscaling/v2beta2 + validate: + message: >- + {{ request.object.apiVersion }}/{{ request.object.kind }} is deprecated and will be removed in v1.26. + See: https://kubernetes.io/docs/reference/using-api/deprecation-guide/ + deny: {} + - name: validate-v1-27-removals + match: + any: + - resources: + kinds: + - storage.k8s.io/*/CSIStorageCapacity + preconditions: + all: + - key: "{{ request.operation || 'BACKGROUND' }}" + operator: NotEquals + value: DELETE + - key: "{{request.object.apiVersion}}" + operator: AnyIn + value: + - storage.k8s.io/v1beta1 + validate: + message: >- + {{ request.object.apiVersion }}/{{ request.object.kind }} is deprecated and will be removed in v1.27. + See: https://kubernetes.io/docs/reference/using-api/deprecation-guide/ + deny: {} + - name: validate-v1-29-removals + match: + any: + - resources: + kinds: + - flowcontrol.apiserver.k8s.io/*/FlowSchema + - flowcontrol.apiserver.k8s.io/*/PriorityLevelConfiguration + preconditions: + all: + - key: "{{ request.operation || 'BACKGROUND' }}" + operator: NotEquals + value: DELETE + - key: "{{request.object.apiVersion}}" + operator: AnyIn + value: + - flowcontrol.apiserver.k8s.io/v1beta2 + validate: + message: >- + {{ request.object.apiVersion }}/{{ request.object.kind }} is deprecated and will be removed in v1.29. + See: https://kubernetes.io/docs/reference/using-api/deprecation-guide/ + deny: {} diff --git a/cluster-config/components/kyverno/overlays/policies/check-openshift-deprecated-apis.yaml b/cluster-config/components/kyverno/overlays/policies/check-openshift-deprecated-apis.yaml new file mode 100644 index 0000000..32beb14 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/check-openshift-deprecated-apis.yaml @@ -0,0 +1,36 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-openshift-deprecated-apis + annotations: + policies.kyverno.io/title: Disallow deprecated APIs + policies.kyverno.io/category: OpenShift + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.20" + policies.kyverno.io/subject: ClusterRole,ClusterRoleBinding,Role,RoleBinding,RBAC + policies.kyverno.io/description: >- + OpenShift APIs are sometimes deprecated and removed after a few releases. + As a best practice, older API versions should be replaced with newer versions. + This policy validates for APIs that are deprecated or scheduled for removal. + Note that checking for some of these resources may require modifying the Kyverno + ConfigMap to remove filters. +spec: + validationFailureAction: enforce + failurePolicy: Ignore + background: false + rules: + - name: check-deprecated-apis + match: + any: + - resources: + kinds: + - authorization.openshift.io/v1/ClusterRole + - authorization.openshift.io/v1/ClusterRoleBinding + - authorization.openshift.io/v1/Role + - authorization.openshift.io/v1/RoleBinding + validate: + message: >- + {{ request.object.apiVersion }}/{{ request.object.kind }} is deprecated. + deny: {} diff --git a/cluster-config/components/kyverno/overlays/policies/disallow-anyuid-scc-policy.yaml b/cluster-config/components/kyverno/overlays/policies/disallow-anyuid-scc-policy.yaml new file mode 100644 index 0000000..6485d06 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/disallow-anyuid-scc-policy.yaml @@ -0,0 +1,56 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-security-context-constraint-anyuid + annotations: + policies.kyverno.io/title: Disallow use of the SecurityContextConstraint (SCC) anyuid + policies.kyverno.io/category: Security + policies.kyverno.io/severity: high + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.20" + policies.kyverno.io/subject: Role,ClusterRole + policies.kyverno.io/description: >- + Disallow the use of the SecurityContextConstraint (SCC) anyuid which allows a pod to run with the UID as declared in the image instead of a random UID +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: check-security-context-constraint + match: + any: + - resources: + kinds: + - ClusterRole + - Role + validate: + message: >- + Use of the SecurityContextConstraint (SCC) anyuid is not allowed + foreach: + - list: request.object.rules[] + deny: + conditions: + all: + - key: anyuid + operator: AnyIn + value: "{{element.resourceNames[]}}" + - key: "{{ element.verbs[] | contains(@, 'use') || contains(@, '*') }}" + operator: Equals + value: true + - name: check-security-context-roleref + match: + any: + - resources: + kinds: + - ClusterRoleBinding + - RoleBinding + validate: + message: >- + Use of the SecurityContextConstraint (SCC) anyuid is not allowed + deny: + conditions: + all: + - key: system:openshift:scc:anyuid + operator: Equals + value: "{{request.object.roleRef.name}}" diff --git a/cluster-config/components/kyverno/overlays/policies/disallow-jenkins-pipeline-strategy.yaml b/cluster-config/components/kyverno/overlays/policies/disallow-jenkins-pipeline-strategy.yaml new file mode 100644 index 0000000..c7e5379 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/disallow-jenkins-pipeline-strategy.yaml @@ -0,0 +1,34 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-jenkins-pipeline-strategy + annotations: + policies.kyverno.io/title: Disallow OpenShift Jenkins Pipeline Build Strategy + policies.kyverno.io/category: OpenShift + policies.kyverno.io/severity: medium + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.20" + policies.kyverno.io/subject: BuildConfig + policies.kyverno.io/description: >- + The Jenkins Pipeline Build Strategy has been deprecated. This policy prevents its use. Use OpenShift Pipelines instead. +spec: + validationFailureAction: enforce + failurePolicy: Ignore + background: false + rules: + - name: check-build-strategy + match: + any: + - resources: + kinds: + - build.openshift.io/v1/BuildConfig + validate: + message: >- + Jenkins Pipeline Build Strategy has been deprecated and is not allowed + deny: + conditions: + all: + - key: "{{ keys(request.object.spec.strategy) | contains(@, 'jenkinsPipelineStrategy') }}" + operator: Equals + value: true diff --git a/cluster-config/components/kyverno/overlays/policies/disallow-latest-tag.yaml b/cluster-config/components/kyverno/overlays/policies/disallow-latest-tag.yaml new file mode 100644 index 0000000..5a58103 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/disallow-latest-tag.yaml @@ -0,0 +1,41 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-latest-tag + annotations: + policies.kyverno.io/title: Disallow Latest Tag + policies.kyverno.io/category: Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + The ':latest' tag is mutable and can lead to unexpected errors if the + image changes. A best practice is to use an immutable tag that maps to + a specific version of an application Pod. This policy validates that the image + specifies a tag and that it is not called `latest`. +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: require-image-tag + match: + resources: + kinds: + - Pod + validate: + message: "An image tag is required." + pattern: + spec: + containers: + - image: "*:*" + - name: validate-image-tag + match: + resources: + kinds: + - Pod + validate: + message: "Using a mutable image tag e.g. 'latest' is not allowed." + pattern: + spec: + containers: + - image: "!*:latest" diff --git a/cluster-config/components/kyverno/overlays/policies/kustomization.yaml b/cluster-config/components/kyverno/overlays/policies/kustomization.yaml new file mode 100644 index 0000000..10ac092 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +commonAnnotations: + argocd.argoproj.io/compare-options: IgnoreExtraneous + +resources: +- ../../base +- validate-probes-policy.yaml +- require-requests-limits-policy.yaml +- disallow-anyuid-scc-policy.yaml +- require-tls-routes.yaml +- check-deprecated-apis.yaml +- check-openshift-deprecated-apis.yaml +- disallow-latest-tag.yaml +- disallow-jenkins-pipeline-strategy.yaml +- application-prevent-default-project.yaml +- application-field-validation.yaml +# - annotate-route-argo-external-link.yaml diff --git a/cluster-config/components/kyverno/overlays/policies/require-requests-limits-policy.yaml b/cluster-config/components/kyverno/overlays/policies/require-requests-limits-policy.yaml new file mode 100644 index 0000000..45b305a --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/require-requests-limits-policy.yaml @@ -0,0 +1,37 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: require-requests-limits + annotations: + policies.kyverno.io/title: Require Limits and Requests + policies.kyverno.io/category: Multi-Tenancy + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + As application workloads share cluster resources, it is important to limit resources + requested and consumed by each Pod. It is recommended to require resource requests and + limits per Pod, especially for memory and CPU. If a Namespace level request or limit is specified, + defaults will automatically be applied to each Pod based on the LimitRange configuration. + This policy validates that all containers have something specified for memory and CPU + requests and memory limits. +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: validate-resources + match: + resources: + kinds: + - Pod + validate: + message: "CPU and memory resource requests and limits are required." + pattern: + spec: + containers: + - resources: + requests: + memory: "?*" + cpu: "?*" + limits: + memory: "?*" diff --git a/cluster-config/components/kyverno/overlays/policies/require-tls-routes.yaml b/cluster-config/components/kyverno/overlays/policies/require-tls-routes.yaml new file mode 100644 index 0000000..489cfa6 --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/require-tls-routes.yaml @@ -0,0 +1,39 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-routes + annotations: + policies.kyverno.io/title: Require TLS routes in OpenShift + policies.kyverno.io/category: OpenShift + policies.kyverno.io/severity: high + kyverno.io/kyverno-version: 1.6.0 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.20" + policies.kyverno.io/subject: Route + policies.kyverno.io/description: |- + HTTP traffic is not encrypted and hence insecure. This policy prevents configuration of OpenShift HTTP routes. +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: require-tls-routes + match: + any: + - resources: + kinds: + - route.openshift.io/v1/Route + preconditions: + all: + - key: "{{ request.operation }}" + operator: NotEquals + value: ["DELETE"] + validate: + message: >- + HTTP routes are not allowed. Configure TLS for secure routes. + deny: + conditions: + all: + - key: "{{ keys(request.object.spec) | contains(@, 'tls') }}" + operator: Equals + value: false diff --git a/cluster-config/components/kyverno/overlays/policies/validate-probes-policy.yaml b/cluster-config/components/kyverno/overlays/policies/validate-probes-policy.yaml new file mode 100644 index 0000000..72c06dd --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/validate-probes-policy.yaml @@ -0,0 +1,37 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: require-pod-probes + annotations: + pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,StatefulSet + policies.kyverno.io/title: Require Pod Probes + policies.kyverno.io/category: Best Practices + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Liveness and readiness probes need to be configured to correctly manage a Pod's + lifecycle during deployments, restarts, and upgrades. For each Pod, a periodic + `livenessProbe` is performed by the kubelet to determine if the Pod's containers + are running or need to be restarted. A `readinessProbe` is used by Services + and Deployments to determine if the Pod is ready to receive network traffic. + This policy validates that all containers have liveness and readiness probes by + ensuring the `periodSeconds` field is greater than zero. +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + rules: + - name: validate-livenessProbe-readinessProbe + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes are required." + pattern: + spec: + containers: + - livenessProbe: + periodSeconds: ">0" + readinessProbe: + periodSeconds: ">0" diff --git a/cluster-config/components/kyverno/overlays/policies/verify-signed-images.yaml b/cluster-config/components/kyverno/overlays/policies/verify-signed-images.yaml new file mode 100644 index 0000000..4c57b6b --- /dev/null +++ b/cluster-config/components/kyverno/overlays/policies/verify-signed-images.yaml @@ -0,0 +1,43 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: verify-signed-image + annotations: + policies.kyverno.io/title: Verify Signed Images + policies.kyverno.io/category: Security + policies.kyverno.io/severity: high + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Validates signed images against specified certificates +spec: + validationFailureAction: audit + failurePolicy: Ignore + background: false + webhookTimeoutSeconds: 30 + rules: + - name: verify-image-quay-io-gnunn-client + match: + any: + - resources: + kinds: + - Pod + verifyImages: + - image: "quay.io/gnunn/client:*" + key: |- + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWno6IupPFSRi9btNhFtMeS1iQbM + gN6OWsfUdhfT5TCf23ESE3vfuMWtX9syvjmemuGpZ+/fRDOyqAbVnAGNpQ== + -----END PUBLIC KEY----- + - name: verify-image-quay-io-gnunn-server + match: + any: + - resources: + kinds: + - Pod + verifyImages: + - image: "quay.io/gnunn/server:*" + key: |- + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWno6IupPFSRi9btNhFtMeS1iQbM + gN6OWsfUdhfT5TCf23ESE3vfuMWtX9syvjmemuGpZ+/fRDOyqAbVnAGNpQ== + -----END PUBLIC KEY----- diff --git a/cluster-config/components/login-template/base/kustomization.yaml b/cluster-config/components/login-template/base/kustomization.yaml new file mode 100644 index 0000000..1a45cc7 --- /dev/null +++ b/cluster-config/components/login-template/base/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-config + +secretGenerator: +- name: matrix-login-template + options: + disableNameSuffixHash: true + files: + - login/login.html +- name: matrix-providers-template + options: + disableNameSuffixHash: true + files: + - login/providers.html diff --git a/cluster-config/components/login-template/base/login/login.html b/cluster-config/components/login-template/base/login/login.html new file mode 100644 index 0000000..0481517 --- /dev/null +++ b/cluster-config/components/login-template/base/login/login.html @@ -0,0 +1,1699 @@ + + + + + + Login + + + + + + + + + + + +
+ +
+ Red Hat OpenShift Container Platform logo +

Log in to your account

+ + + + {{ if .Error }} +
{{ .Error }}
+ + {{ end }} + +
+ + +
+ +
+ + +
+
+ +
+ +
+
+ + + + diff --git a/cluster-config/components/login-template/base/login/providers.html b/cluster-config/components/login-template/base/login/providers.html new file mode 100644 index 0000000..4d1c001 --- /dev/null +++ b/cluster-config/components/login-template/base/login/providers.html @@ -0,0 +1,772 @@ + + + + Login + + + + + + + + + + +
+
+ Red Hat OpenShift Container Platform logo + {{ if eq (len .Providers) 1}} +
+ Log In +
+ {{ else }} +

Log in with...

+ {{ range $provider := .Providers }} + + {{ end }} {{ end }} +
+
+ + + diff --git a/cluster-config/components/loki/instance/base/clusterlogforwarder.yaml b/cluster-config/components/loki/instance/base/clusterlogforwarder.yaml new file mode 100644 index 0000000..99350b3 --- /dev/null +++ b/cluster-config/components/loki/instance/base/clusterlogforwarder.yaml @@ -0,0 +1,39 @@ +apiVersion: logging.openshift.io/v1 +kind: ClusterLogForwarder +metadata: + name: instance + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + outputs: + - name: loki-app + type: loki + url: http://lokistack-gateway-http.openshift-logging.svc:8080/api/logs/v1/application + secret: + name: lokistack-gateway-bearer-token + - name: loki-infra + type: loki + url: http://lokistack-gateway-http.openshift-logging.svc:8080/api/logs/v1/infrastructure + secret: + name: lokistack-gateway-bearer-token + - name: loki-audit + type: loki + url: http://lokistack-gateway-http.openshift-logging.svc:8080/api/logs/v1/audit + secret: + name: lokistack-gateway-bearer-token + pipelines: + - name: send-app-logs + inputRefs: + - application + outputRefs: + - loki-app + - name: send-infra-logs + inputRefs: + - infrastructure + outputRefs: + - loki-infra + - name: send-audit-logs + inputRefs: + - audit + outputRefs: + - loki-audit diff --git a/cluster-config/components/loki/instance/base/clusterlogging.yaml b/cluster-config/components/loki/instance/base/clusterlogging.yaml new file mode 100644 index 0000000..bdeaa5e --- /dev/null +++ b/cluster-config/components/loki/instance/base/clusterlogging.yaml @@ -0,0 +1,14 @@ +apiVersion: logging.openshift.io/v1 +kind: ClusterLogging +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + name: instance +spec: + managementState: Managed + logStore: + type: lokistack + lokistack: + name: logging-loki + collection: + type: vector diff --git a/cluster-config/components/loki/instance/base/kustomization.yaml b/cluster-config/components/loki/instance/base/kustomization.yaml new file mode 100644 index 0000000..8a389df --- /dev/null +++ b/cluster-config/components/loki/instance/base/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-logging + +resources: +- lokigateway-secret.yaml +# - role.yaml +- lokistack.yaml +# - clusterlogforwarder.yaml +- clusterlogging.yaml diff --git a/cluster-config/components/loki/instance/base/lokigateway-secret.yaml b/cluster-config/components/loki/instance/base/lokigateway-secret.yaml new file mode 100644 index 0000000..06204d9 --- /dev/null +++ b/cluster-config/components/loki/instance/base/lokigateway-secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +data: + token: L3Zhci9ydW4vc2VjcmV0cy9rdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3Rva2Vu +kind: Secret +metadata: + name: lokistack-gateway-bearer-token +type: Opaque diff --git a/cluster-config/components/loki/instance/base/lokistack.yaml b/cluster-config/components/loki/instance/base/lokistack.yaml new file mode 100644 index 0000000..5b33448 --- /dev/null +++ b/cluster-config/components/loki/instance/base/lokistack.yaml @@ -0,0 +1,18 @@ +apiVersion: loki.grafana.com/v1 +kind: LokiStack +metadata: + name: logging-loki + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + size: 1x.extra-small + storage: + schemas: + - effectiveDate: '2022-06-01' + version: v12 + secret: + name: loki-storage + type: s3 + storageClassName: lvms-vg1 + tenants: + mode: openshift-logging diff --git a/cluster-config/components/loki/instance/base/role.yaml b/cluster-config/components/loki/instance/base/role.yaml new file mode 100644 index 0000000..79f8c42 --- /dev/null +++ b/cluster-config/components/loki/instance/base/role.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: lokistack-tenant-logs +rules: +- apiGroups: + - 'loki.grafana.com' + resources: + - application + - infrastructure + - audit + resourceNames: + - logs + verbs: + - 'create' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: lokistack-tenant-logs +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: lokistack-tenant-logs +subjects: +- kind: ServiceAccount + name: logcollector + namespace: openshift-logging diff --git a/cluster-config/components/loki/instance/overlays/sno/ingestion-rate-patch.yaml b/cluster-config/components/loki/instance/overlays/sno/ingestion-rate-patch.yaml new file mode 100644 index 0000000..7a29077 --- /dev/null +++ b/cluster-config/components/loki/instance/overlays/sno/ingestion-rate-patch.yaml @@ -0,0 +1,11 @@ +apiVersion: loki.grafana.com/v1beta1 +kind: LokiStack +metadata: + name: lokistack +spec: + limits: + global: + ingestion: + ingestionRate: 12 + ingestionBurstSize: 15 + size: 1x.extra-small diff --git a/cluster-config/components/loki/instance/overlays/sno/kustomization.yaml b/cluster-config/components/loki/instance/overlays/sno/kustomization.yaml new file mode 100644 index 0000000..5fa069c --- /dev/null +++ b/cluster-config/components/loki/instance/overlays/sno/kustomization.yaml @@ -0,0 +1,20 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-logging + +resources: +- ../../base + +patches: +- patch: |- + - op: replace + path: /spec/size + value: 1x.extra-small + target: + kind: LokiStack + name: logging-loki +- path: ingestion-rate-patch.yaml + target: + kind: LokiStack + name: logging-loki diff --git a/cluster-config/components/loki/operator/cluster-logging/base/kustomization.yaml b/cluster-config/components/loki/operator/cluster-logging/base/kustomization.yaml new file mode 100644 index 0000000..678b783 --- /dev/null +++ b/cluster-config/components/loki/operator/cluster-logging/base/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-logging + +resources: +- namespace.yaml +- operatorgroup.yaml +- subscription.yaml diff --git a/cluster-config/components/loki/operator/cluster-logging/base/namespace.yaml b/cluster-config/components/loki/operator/cluster-logging/base/namespace.yaml new file mode 100644 index 0000000..2d1cfd0 --- /dev/null +++ b/cluster-config/components/loki/operator/cluster-logging/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-logging diff --git a/cluster-config/components/loki/operator/cluster-logging/base/operatorgroup.yaml b/cluster-config/components/loki/operator/cluster-logging/base/operatorgroup.yaml new file mode 100644 index 0000000..06b23d8 --- /dev/null +++ b/cluster-config/components/loki/operator/cluster-logging/base/operatorgroup.yaml @@ -0,0 +1,7 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-logging +spec: + targetNamespaces: + - openshift-logging diff --git a/cluster-config/components/loki/operator/cluster-logging/base/subscription.yaml b/cluster-config/components/loki/operator/cluster-logging/base/subscription.yaml new file mode 100644 index 0000000..ad10122 --- /dev/null +++ b/cluster-config/components/loki/operator/cluster-logging/base/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: cluster-logging +spec: + channel: stable-5.5 + installPlanApproval: Automatic + name: cluster-logging + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/loki/operator/loki/base/kustomization.yaml b/cluster-config/components/loki/operator/loki/base/kustomization.yaml new file mode 100644 index 0000000..a6f982b --- /dev/null +++ b/cluster-config/components/loki/operator/loki/base/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-operators-redhat + +resources: +- namespace.yaml +- operatorgroup.yaml +- subscription.yaml diff --git a/cluster-config/components/loki/operator/loki/base/namespace.yaml b/cluster-config/components/loki/operator/loki/base/namespace.yaml new file mode 100644 index 0000000..41501f2 --- /dev/null +++ b/cluster-config/components/loki/operator/loki/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-operators-redhat diff --git a/cluster-config/components/loki/operator/loki/base/operatorgroup.yaml b/cluster-config/components/loki/operator/loki/base/operatorgroup.yaml new file mode 100644 index 0000000..b1b447a --- /dev/null +++ b/cluster-config/components/loki/operator/loki/base/operatorgroup.yaml @@ -0,0 +1,5 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-operators-redhat +spec: {} diff --git a/cluster-config/components/loki/operator/loki/base/subscription.yaml b/cluster-config/components/loki/operator/loki/base/subscription.yaml new file mode 100644 index 0000000..a15b07a --- /dev/null +++ b/cluster-config/components/loki/operator/loki/base/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: loki-operator +spec: + channel: stable + installPlanApproval: Automatic + name: loki-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/lvm-operator/base/kustomization.yaml b/cluster-config/components/lvm-operator/base/kustomization.yaml new file mode 100644 index 0000000..c75dae2 --- /dev/null +++ b/cluster-config/components/lvm-operator/base/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-storage + +resources: + - subscription.yaml + - lvmcluster.yaml diff --git a/cluster-config/components/lvm-operator/base/lvmcluster.yaml b/cluster-config/components/lvm-operator/base/lvmcluster.yaml new file mode 100644 index 0000000..2c167ba --- /dev/null +++ b/cluster-config/components/lvm-operator/base/lvmcluster.yaml @@ -0,0 +1,16 @@ +apiVersion: lvm.topolvm.io/v1alpha1 +kind: LVMCluster +metadata: + name: lvmcluster + namespace: openshift-storage + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true +spec: + storage: + deviceClasses: + - name: vg1 + default: true + thinPoolConfig: + name: thin-pool-1 + overprovisionRatio: 10 + sizePercent: 90 diff --git a/cluster-config/components/lvm-operator/base/subscription.yaml b/cluster-config/components/lvm-operator/base/subscription.yaml new file mode 100644 index 0000000..3f9f810 --- /dev/null +++ b/cluster-config/components/lvm-operator/base/subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: lvms-operator + namespace: openshift-storage +spec: + channel: stable-4.17 + installPlanApproval: Automatic + name: lvms-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/lvm-operator/overlays/standalone/kustomization.yaml b/cluster-config/components/lvm-operator/overlays/standalone/kustomization.yaml new file mode 100644 index 0000000..b7be712 --- /dev/null +++ b/cluster-config/components/lvm-operator/overlays/standalone/kustomization.yaml @@ -0,0 +1,4 @@ +resources: +- ../../base +- namespace.yaml +- operatorgroup.yaml diff --git a/cluster-config/components/lvm-operator/overlays/standalone/namespace.yaml b/cluster-config/components/lvm-operator/overlays/standalone/namespace.yaml new file mode 100644 index 0000000..71549fb --- /dev/null +++ b/cluster-config/components/lvm-operator/overlays/standalone/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-storage diff --git a/cluster-config/components/lvm-operator/overlays/standalone/operatorgroup.yaml b/cluster-config/components/lvm-operator/overlays/standalone/operatorgroup.yaml new file mode 100644 index 0000000..4f4024d --- /dev/null +++ b/cluster-config/components/lvm-operator/overlays/standalone/operatorgroup.yaml @@ -0,0 +1,9 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-storage + namespace: openshift-storage +spec: + targetNamespaces: + - openshift-storage + upgradeStrategy: Default diff --git a/cluster-config/components/oauth/base/kustomization.yaml b/cluster-config/components/oauth/base/kustomization.yaml new file mode 100644 index 0000000..15fa2c6 --- /dev/null +++ b/cluster-config/components/oauth/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- oauth.yaml diff --git a/cluster-config/components/oauth/base/oauth.yaml b/cluster-config/components/oauth/base/oauth.yaml new file mode 100644 index 0000000..bf7f937 --- /dev/null +++ b/cluster-config/components/oauth/base/oauth.yaml @@ -0,0 +1,6 @@ +apiVersion: config.openshift.io/v1 +kind: OAuth +metadata: + name: cluster +spec: + identityProviders: [] diff --git a/cluster-config/components/oauth/overlays/glauth/kustomization.yaml b/cluster-config/components/oauth/overlays/glauth/kustomization.yaml new file mode 100644 index 0000000..8d16ac3 --- /dev/null +++ b/cluster-config/components/oauth/overlays/glauth/kustomization.yaml @@ -0,0 +1,32 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +resources: +- ldap-external-secret.yaml + +patches: + - patch: |- + - op: add + path: /spec/identityProviders/- + value: + name: Internal + mappingMethod: claim + type: LDAP + ldap: + attributes: + id: + - dn + name: + - cn + preferredUsername: + - uid + bindDN: "openshift,dc=ocplab,dc=com" + bindPassword: + name: ldap-secret + insecure: true + url: "ldap://infra-server/ou=users,dc=ocplab,dc=com?uid" + target: + group: config.openshift.io + kind: OAuth + name: cluster + version: v1 diff --git a/cluster-config/components/oauth/overlays/glauth/ldap-external-secret.yaml b/cluster-config/components/oauth/overlays/glauth/ldap-external-secret.yaml new file mode 100644 index 0000000..a156ffa --- /dev/null +++ b/cluster-config/components/oauth/overlays/glauth/ldap-external-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: ldap-secret + namespace: openshift-config +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: ldap-secret + data: + - secretKey: bindPassword + remoteRef: + key: LDAP diff --git a/cluster-config/components/oauth/overlays/google/google-client-secret.yaml b/cluster-config/components/oauth/overlays/google/google-client-secret.yaml new file mode 100644 index 0000000..15463eb --- /dev/null +++ b/cluster-config/components/oauth/overlays/google/google-client-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: google-secret + namespace: openshift-config +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: google-secret + data: + - secretKey: clientSecret + remoteRef: + key: GOOGLE_SSO diff --git a/cluster-config/components/oauth/overlays/google/kustomization.yaml b/cluster-config/components/oauth/overlays/google/kustomization.yaml new file mode 100644 index 0000000..471c59e --- /dev/null +++ b/cluster-config/components/oauth/overlays/google/kustomization.yaml @@ -0,0 +1,24 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +resources: +- google-client-secret.yaml + +patches: + - patch: |- + - op: add + path: /spec/identityProviders/- + value: + google: + clientID: 853224504221-d1vvbaokui9cnq5ge7pcih1sfl26sq69.apps.googleusercontent.com + clientSecret: + name: google-secret + hostedDomain: redhat.com + mappingMethod: claim + name: RedHatSSO + type: Google + target: + group: config.openshift.io + kind: OAuth + name: cluster + version: v1 diff --git a/cluster-config/components/oauth/overlays/google/patch-google-idp.yaml b/cluster-config/components/oauth/overlays/google/patch-google-idp.yaml new file mode 100644 index 0000000..83ee5f5 --- /dev/null +++ b/cluster-config/components/oauth/overlays/google/patch-google-idp.yaml @@ -0,0 +1,11 @@ +- op: add + path: /spec/identityProviders/1 + value: + google: + clientID: 853224504221-d1vvbaokui9cnq5ge7pcih1sfl26sq69.apps.googleusercontent.com + clientSecret: + name: google-secret + hostedDomain: redhat.com + mappingMethod: claim + name: RedHatSSO + type: Google diff --git a/cluster-config/components/oauth/overlays/homelab/kustomization.yaml b/cluster-config/components/oauth/overlays/homelab/kustomization.yaml new file mode 100644 index 0000000..e208aae --- /dev/null +++ b/cluster-config/components/oauth/overlays/homelab/kustomization.yaml @@ -0,0 +1,5 @@ +resources: +- ../../base + +components: +- ../sso diff --git a/cluster-config/components/oauth/overlays/htpass/htpass-secret-external.yaml b/cluster-config/components/oauth/overlays/htpass/htpass-secret-external.yaml new file mode 100644 index 0000000..536accb --- /dev/null +++ b/cluster-config/components/oauth/overlays/htpass/htpass-secret-external.yaml @@ -0,0 +1,15 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: htpass-secret + namespace: openshift-config +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: htpass-secret + data: + - secretKey: htpasswd + remoteRef: + key: HTPASSWD diff --git a/cluster-config/components/oauth/overlays/htpass/kustomization.yaml b/cluster-config/components/oauth/overlays/htpass/kustomization.yaml new file mode 100644 index 0000000..ace7c6c --- /dev/null +++ b/cluster-config/components/oauth/overlays/htpass/kustomization.yaml @@ -0,0 +1,19 @@ +resources: + - htpass-secret-external.yaml + +patches: + - patch: |- + - op: add + path: /spec/identityProviders/1 + value: + htpasswd: + fileData: + name: htpass-secret + mappingMethod: claim + name: htpasswd + type: HTPasswd + target: + group: config.openshift.io + kind: OAuth + name: cluster + version: v1 diff --git a/cluster-config/components/oauth/overlays/matrix-template/README.md b/cluster-config/components/oauth/overlays/matrix-template/README.md new file mode 100644 index 0000000..9b5372b --- /dev/null +++ b/cluster-config/components/oauth/overlays/matrix-template/README.md @@ -0,0 +1,3 @@ +From the OpenShift Developer Console contest, see original repo here: + +https://github.com/kenmoini/openshift-web-console-customizations/tree/master/competition/kenmoini diff --git a/cluster-config/components/oauth/overlays/matrix-template/kustomization.yaml b/cluster-config/components/oauth/overlays/matrix-template/kustomization.yaml new file mode 100644 index 0000000..25cfdc6 --- /dev/null +++ b/cluster-config/components/oauth/overlays/matrix-template/kustomization.yaml @@ -0,0 +1,20 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +resources: + - ../../../login-template/base + +patches: + - patch: |- + - op: add + path: /spec/templates + value: + login: + name: matrix-login-template + providerSelection: + name: matrix-providers-template + target: + group: config.openshift.io + kind: OAuth + name: cluster + version: v1 diff --git a/cluster-config/components/oauth/overlays/sso/console.yaml b/cluster-config/components/oauth/overlays/sso/console.yaml new file mode 100644 index 0000000..cdd94f5 --- /dev/null +++ b/cluster-config/components/oauth/overlays/sso/console.yaml @@ -0,0 +1,12 @@ +apiVersion: config.openshift.io/v1 +kind: Console +metadata: + annotations: + include.release.openshift.io/ibm-cloud-managed: "true" + include.release.openshift.io/self-managed-high-availability: "true" + include.release.openshift.io/single-node-developer: "true" + release.openshift.io/create-only: "true" + name: cluster +spec: + authentication: + logoutRedirect: https://sso.ocplab.com/realms/ocplab/protocol/openid-connect/logout?client_id=openshift&post_logout_redirect_uri=https://console-openshift-console.${SUB_DOMAIN} diff --git a/cluster-config/components/oauth/overlays/sso/kustomization.yaml b/cluster-config/components/oauth/overlays/sso/kustomization.yaml new file mode 100644 index 0000000..2bf4f55 --- /dev/null +++ b/cluster-config/components/oauth/overlays/sso/kustomization.yaml @@ -0,0 +1,43 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +resources: +- oidc-client-secret.yaml +- console.yaml + +patches: + - patch: |- + - op: add + path: /spec/identityProviders/- + value: + name: LabSSO + mappingMethod: claim + type: OpenID + openID: + clientID: openshift + clientSecret: + name: oidc-client-secret + extraScopes: + - email + - profile + extraAuthorizeParameters: + include_granted_scopes: "true" + claims: + preferredUsername: + - preferred_username + - email + name: + - nickname + - given_name + - name + email: + - custom_email_claim + - email + groups: + - groups + issuer: https://sso.ocplab.com/realms/ocplab + target: + group: config.openshift.io + kind: OAuth + name: cluster + version: v1 diff --git a/cluster-config/components/oauth/overlays/sso/oidc-client-secret.yaml b/cluster-config/components/oauth/overlays/sso/oidc-client-secret.yaml new file mode 100644 index 0000000..12baba3 --- /dev/null +++ b/cluster-config/components/oauth/overlays/sso/oidc-client-secret.yaml @@ -0,0 +1,15 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: oidc-client-secret + namespace: openshift-config +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: oidc-client-secret + data: + - secretKey: clientSecret + remoteRef: + key: OIDC_OCPLAB diff --git a/cluster-config/components/odf-operator/instance/base/kustomization.yaml b/cluster-config/components/odf-operator/instance/base/kustomization.yaml new file mode 100644 index 0000000..6f694d7 --- /dev/null +++ b/cluster-config/components/odf-operator/instance/base/kustomization.yaml @@ -0,0 +1,4 @@ +resources: +- storage-cluster.yaml +- storage-system.yaml +- noobaa-default-backing-store.yaml diff --git a/cluster-config/components/odf-operator/instance/base/noobaa-default-backing-store.yaml b/cluster-config/components/odf-operator/instance/base/noobaa-default-backing-store.yaml new file mode 100644 index 0000000..a0fc582 --- /dev/null +++ b/cluster-config/components/odf-operator/instance/base/noobaa-default-backing-store.yaml @@ -0,0 +1,15 @@ +apiVersion: noobaa.io/v1alpha1 +kind: BackingStore +metadata: + labels: + app: noobaa + name: noobaa-default-backing-store + namespace: openshift-storage +spec: + pvPool: + numVolumes: 1 + resources: + requests: + storage: 200Gi + storageClass: lvms-vg1 + type: pv-pool diff --git a/cluster-config/components/odf-operator/instance/base/storage-cluster.yaml b/cluster-config/components/odf-operator/instance/base/storage-cluster.yaml new file mode 100644 index 0000000..a0681e3 --- /dev/null +++ b/cluster-config/components/odf-operator/instance/base/storage-cluster.yaml @@ -0,0 +1,9 @@ +apiVersion: ocs.openshift.io/v1 +kind: StorageCluster +metadata: + name: ocs-storagecluster + namespace: openshift-storage +spec: + multiCloudGateway: + dbStorageClassName: lvms-vg1 + reconcileStrategy: standalone diff --git a/cluster-config/components/odf-operator/instance/base/storage-system.yaml b/cluster-config/components/odf-operator/instance/base/storage-system.yaml new file mode 100644 index 0000000..06e37e3 --- /dev/null +++ b/cluster-config/components/odf-operator/instance/base/storage-system.yaml @@ -0,0 +1,9 @@ +apiVersion: odf.openshift.io/v1alpha1 +kind: StorageSystem +metadata: + name: ocs-storagecluster-storagesystem + namespace: openshift-storage +spec: + kind: storagecluster.ocs.openshift.io/v1 + name: ocs-storagecluster + namespace: openshift-storage diff --git a/cluster-config/components/odf-operator/operator/overlays/no-registry/kustomization.yaml b/cluster-config/components/odf-operator/operator/overlays/no-registry/kustomization.yaml new file mode 100644 index 0000000..9eaad69 --- /dev/null +++ b/cluster-config/components/odf-operator/operator/overlays/no-registry/kustomization.yaml @@ -0,0 +1,55 @@ +resources: +- github.com/redhat-cop/gitops-catalog/openshift-data-foundation-operator/operator/overlays/stable-4.16 + +patches: + - patch: |- + - op: replace + path: /spec/template/spec/containers/0/image + value: registry.redhat.io/openshift4/ose-cli:latest + target: + kind: Job + name: enable-odf-console-plugin + - patch: |- + - op: replace + path: /spec/channel + value: stable-4.17 + target: + kind: Subscription + name: odf-operator + - patch: |- + - op: replace + path: /apiVersion + value: console.openshift.io/v1 + - op: replace + path: /spec + value: + backend: + service: + basePath: / + name: odf-console-service + namespace: openshift-storage + port: 9001 + type: Service + displayName: ODF Plugin + i18n: + loadType: "" + proxy: + - alias: provider-proxy + authorization: UserToken + endpoint: + service: + name: ux-backend-proxy + namespace: openshift-storage + port: 8888 + type: Service + - alias: rosa-prometheus + authorization: None + endpoint: + service: + name: prometheus + namespace: openshift-storage + port: 9339 + type: Service + target: + kind: ConsolePlugin + name: odf-console diff --git a/cluster-config/components/openshift-monitoring/README.md b/cluster-config/components/openshift-monitoring/README.md new file mode 100644 index 0000000..6c2c551 --- /dev/null +++ b/cluster-config/components/openshift-monitoring/README.md @@ -0,0 +1,4 @@ +This is used to configure a couple of things with openshift-monitoring: + +1. Sets the cluster label so that it can be referenced in templates. This lets us include the cluster name in the received alerts +2. Sets up a service account that external monitoring tools can use to query thanos, the bearer token can be retrieved from the secret. diff --git a/cluster-config/components/openshift-monitoring/base/cluster-monitoring-config-cm.yaml b/cluster-config/components/openshift-monitoring/base/cluster-monitoring-config-cm.yaml new file mode 100644 index 0000000..81bf45c --- /dev/null +++ b/cluster-config/components/openshift-monitoring/base/cluster-monitoring-config-cm.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cluster-monitoring-config + namespace: openshift-monitoring +data: + config.yaml: | + alertmanagerMain: + enableUserAlertmanagerConfig: true + enableUserWorkload: true + nodeExporter: + collectors: + buddyinfo: {} + cpufreq: {} + ksmd: {} + mountstats: {} + netclass: {} + netdev: {} + processes: {} + systemd: {} + tcpstat: {} + prometheusK8s: + additionalAlertmanagerConfigs: + - apiVersion: v2 + bearerToken: + key: token + name: observability-alertmanager-accessor + scheme: https + staticConfigs: + - alertmanager-open-cluster-management-observability.apps.hub.ocplab.com + tlsConfig: + ca: + key: service-ca.crt + name: hub-alertmanager-router-ca + insecureSkipVerify: false + externalLabels: + cluster: ${CLUSTER_GITOPS_NAME} + managed_cluster: ${CLUSTER_ID} + volumeClaimTemplate: + metadata: {} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 40Gi + volumeMode: Filesystem + status: {} diff --git a/cluster-config/components/openshift-monitoring/base/kustomization.yaml b/cluster-config/components/openshift-monitoring/base/kustomization.yaml new file mode 100644 index 0000000..454202e --- /dev/null +++ b/cluster-config/components/openshift-monitoring/base/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - cluster-monitoring-config-cm.yaml + - monitoring-role-binding.yaml + - service-account.yaml + - token-secret.yaml diff --git a/cluster-config/components/openshift-monitoring/base/monitoring-role-binding.yaml b/cluster-config/components/openshift-monitoring/base/monitoring-role-binding.yaml new file mode 100644 index 0000000..b7a0f7d --- /dev/null +++ b/cluster-config/components/openshift-monitoring/base/monitoring-role-binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: external-monitor-reader +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-monitoring-view +subjects: +- kind: ServiceAccount + name: external-monitor-reader + namespace: openshift-monitoring diff --git a/cluster-config/components/openshift-monitoring/base/service-account.yaml b/cluster-config/components/openshift-monitoring/base/service-account.yaml new file mode 100644 index 0000000..0323f72 --- /dev/null +++ b/cluster-config/components/openshift-monitoring/base/service-account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-monitor-reader + namespace: openshift-monitoring diff --git a/cluster-config/components/openshift-monitoring/base/token-secret.yaml b/cluster-config/components/openshift-monitoring/base/token-secret.yaml new file mode 100644 index 0000000..222d52a --- /dev/null +++ b/cluster-config/components/openshift-monitoring/base/token-secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/service-account.name: external-monitor-reader + name: external-monitor-reader + namespace: openshift-monitoring +type: kubernetes.io/service-account-token diff --git a/cluster-config/components/pipelines-operator/base/kustomization.yaml b/cluster-config/components/pipelines-operator/base/kustomization.yaml new file mode 100644 index 0000000..51735d2 --- /dev/null +++ b/cluster-config/components/pipelines-operator/base/kustomization.yaml @@ -0,0 +1,5 @@ +resources: +- subscription.yaml +- tekton-config.yaml +# Partial needs more work, even with sync wave it fails. Suspect TektonInstaller needs health check so this doesn't get applied until it's ready +# - tekton-config-metrics-partial.yaml diff --git a/cluster-config/components/pipelines-operator/base/subscription.yaml b/cluster-config/components/pipelines-operator/base/subscription.yaml new file mode 100644 index 0000000..baa994a --- /dev/null +++ b/cluster-config/components/pipelines-operator/base/subscription.yaml @@ -0,0 +1,13 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + labels: + operators.coreos.com/openshift-pipelines-operator-rh.openshift-operators: "" + name: openshift-pipelines-operator-rh + namespace: openshift-operators +spec: + channel: pipelines-1.18 + installPlanApproval: Automatic + name: openshift-pipelines-operator-rh + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/pipelines-operator/base/tekton-config-metrics-partial.yaml b/cluster-config/components/pipelines-operator/base/tekton-config-metrics-partial.yaml new file mode 100644 index 0000000..624c2f4 --- /dev/null +++ b/cluster-config/components/pipelines-operator/base/tekton-config-metrics-partial.yaml @@ -0,0 +1,13 @@ +apiVersion: operator.tekton.dev/v1alpha1 +kind: TektonConfig +metadata: + name: config + annotations: + argocd.argoproj.io/sync-options: Validate=false,ServerSideApply=true, SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "99" +spec: + pipeline: + metrics.taskrun.level: taskrun + metrics.pipelinerun.level: pipelinerun + metrics.taskrun.duration-type: lastvalue + metrics.pipelinerun.duration-type: lastvalue diff --git a/cluster-config/components/pipelines-operator/base/tekton-config.yaml b/cluster-config/components/pipelines-operator/base/tekton-config.yaml new file mode 100644 index 0000000..27f5e2b --- /dev/null +++ b/cluster-config/components/pipelines-operator/base/tekton-config.yaml @@ -0,0 +1,129 @@ +apiVersion: operator.tekton.dev/v1alpha1 +kind: TektonConfig +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + ## Do last to overwrite default rather then other way arround + argocd.argoproj.io/sync-wave: "99" + name: config +spec: + addon: + params: + - name: clusterTasks + value: "true" + - name: pipelineTemplates + value: "true" + - name: communityClusterTasks + value: "true" + - name: resolverTasks + value: 'true' + - name: resolverStepActions + value: 'true' + - name: communityResolverTasks + value: 'true' + chain: + artifacts.taskrun.format: in-toto + artifacts.taskrun.storage: tekton + artifacts.taskrun.signer: x509 + artifacts.oci.storage: oci + artifacts.oci.format: simplesigning + artifacts.oci.signer: x509 + transparency.enabled: "true" + dashboard: + options: + disabled: false + readonly: false + hub: + options: + disabled: false + params: + - name: createRbacResource + value: "true" + pipeline: + await-sidecar-readiness: true + coschedule: workspaces + default-service-account: pipeline + disable-affinity-assistant: true + disable-creds-init: false + enable-api-fields: beta + enable-bundles-resolver: true + enable-cel-in-whenexpression: false + enable-cluster-resolver: true + enable-custom-tasks: true + enable-git-resolver: true + enable-hub-resolver: true + enable-param-enum: false + enable-provenance-in-status: false + enable-step-actions: true + enforce-nonfalsifiability: none + git-resolver-config: + default-revision: main + fetch-timeout: 1m + default-url: https://github.com/gnunn-gitops/tekton-catalog + keep-pod-on-cancel: false + max-result-size: 4096 + metrics.count.enable-reason: false + metrics.pipelinerun.duration-type: lastvalue + metrics.pipelinerun.level: pipelinerun + metrics.taskrun.duration-type: lastvalue + metrics.taskrun.level: taskrun + options: + disabled: false + params: + - name: enableMetrics + value: "true" + performance: + disable-ha: false + require-git-ssh-secret-known-hosts: false + results-from: termination-message + running-in-environment-with-injected-sidecars: true + send-cloudevents-for-runs: false + set-security-context: false + trusted-resources-verification-no-match-policy: ignore + platforms: + openshift: + pipelinesAsCode: + enable: true + options: + disabled: false + settings: + application-name: Pipelines as Code CI + auto-configure-new-github-repo: "false" + bitbucket-cloud-check-source-ip: "true" + auto-configure-repo-namespace-template: "" + bitbucket-cloud-additional-source-ip: "" + custom-console-name: "" + custom-console-url: "" + custom-console-url-namespace: "" + custom-console-url-pr-details: "" + custom-console-url-pr-tasklog: "" + default-max-keep-runs: "0" + error-detection-from-container-logs: "true" + error-detection-max-number-of-lines: "50" + error-detection-simple-regexp: ^(?P[^:]*):(?P[0-9]+):(?P[0-9]+):([ + ]*)?(?P.*) + error-log-snippet: "true" + hub-catalog-name: tekton + hub-url: https://api.hub.tekton.dev/v1 + max-keep-run-upper-limit: "0" + remember-ok-to-test: "true" + remote-tasks: "true" + secret-auto-create: "true" + secret-github-app-scope-extra-repos: "" + secret-github-app-token-scoped: "true" + tekton-dashboard-url: "" + scc: + default: pipelines-scc + profile: all + pruner: + disabled: false + keep: 100 + resources: + - pipelinerun + schedule: 0 8 * * * + targetNamespace: openshift-pipelines + trigger: + default-service-account: pipeline + enable-api-fields: stable + options: + disabled: false diff --git a/cluster-config/components/pipelines-operator/overlays/chains/kustomization.yaml b/cluster-config/components/pipelines-operator/overlays/chains/kustomization.yaml new file mode 100644 index 0000000..3556d65 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/chains/kustomization.yaml @@ -0,0 +1,68 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../base +- openshift-pipelines-namespace.yaml +- oidc-token-refresh-sa.yaml +# - signing-cert-external.yaml +- oidc-info-secret.yaml +- oidc-token-refresher-deploy.yaml + +patches: + - target: + kind: TektonConfig + name: config + patch: | + - op: replace + path: /spec/chain + value: + signers.x509.fulcio.enabled: true + artifacts.taskrun.storage: oci + artifacts.pipelinerun.storage: oci + artifacts.pipelinerun.format: in-toto + transparency.enabled: 'true' + artifacts.taskrun.format: in-toto + signers.x509.tuf.mirror.url: 'https://tuf-trusted-artifact-signer.apps.hub.ocplab.com' + artifacts.oci.signer: x509 + signers.x509.fulcio.address: 'https://fulcio-server-trusted-artifact-signer.apps.hub.ocplab.com' + artifacts.oci.storage: oci + signers.x509.fulcio.issuer: 'https://sso.ocplab.com/realms/ocplab' + transparency.url: 'https://rekor-server-trusted-artifact-signer.apps.hub.ocplab.com' + disabled: false + artifacts.oci.format: simplesigning + options: + deployments: + tekton-chains-controller: + metadata: + creationTimestamp: null + spec: + selector: null + strategy: {} + template: + metadata: + creationTimestamp: null + spec: + containers: + - env: + - name: TUF_ROOT + value: /tuf + name: tekton-chains-controller + resources: {} + volumeMounts: + - mountPath: /tuf + name: tuf + - mountPath: /var/run/sigstore/cosign + name: oidc-info + volumes: + - name: tuf + - name: oidc-info + secret: + items: + - key: id-token + path: oidc-token + secretName: oidc-token + status: {} + disabled: false + signers.x509.identity.token.file: /var/run/sigstore/cosign/oidc-token + artifacts.taskrun.signer: x509 diff --git a/cluster-config/components/pipelines-operator/overlays/chains/oidc-info-secret.yaml b/cluster-config/components/pipelines-operator/overlays/chains/oidc-info-secret.yaml new file mode 100644 index 0000000..c7a49b3 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/chains/oidc-info-secret.yaml @@ -0,0 +1,18 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: oidc-info + namespace: openshift-pipelines +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: oidc-info + creationPolicy: Owner + dataFrom: + - extract: + key: OIDC_INFO diff --git a/cluster-config/components/pipelines-operator/overlays/chains/oidc-token-refresh-sa.yaml b/cluster-config/components/pipelines-operator/overlays/chains/oidc-token-refresh-sa.yaml new file mode 100644 index 0000000..33bd55b --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/chains/oidc-token-refresh-sa.yaml @@ -0,0 +1,36 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: oidc-token-refresher + namespace: openshift-pipelines +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create + - patch + - update + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: oidc-token-refresher + namespace: openshift-pipelines +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: oidc-token-refresher +subjects: +- kind: ServiceAccount + name: oidc-token-refresher + namespace: openshift-pipelines +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: oidc-token-refresher + namespace: openshift-pipelines diff --git a/cluster-config/components/pipelines-operator/overlays/chains/oidc-token-refresher-deploy.yaml b/cluster-config/components/pipelines-operator/overlays/chains/oidc-token-refresher-deploy.yaml new file mode 100644 index 0000000..bbf4ea0 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/chains/oidc-token-refresher-deploy.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: oidc-token-refresher + namespace: openshift-pipelines +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: oidc-token-refresher + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: oidc-token-refresher + deployment: oidc-token-refresher + spec: + containers: + - command: + - sh + - -c + - | + #!/bin/bash + set -o pipefail + while true; do + JWT_TOKEN=$(curl -sL --location "${OIDC_TOKEN_ENDPOINT}" \ + --header "Content-Type: application/x-www-form-urlencoded" \ + --data-urlencode "grant_type=client_credentials" \ + --data-urlencode "client_id=${OIDC_CLIENT_ID}" \ + --data-urlencode "client_secret=${OIDC_CLIENT_SECRET}" \ + --data-urlencode "scope=openid" | jq -r '.id_token') + kubectl create secret generic oidc-token --from-literal=id-token=${JWT_TOKEN} --dry-run=client -o yaml | kubectl apply -f- + sleep 120 + done + envFrom: + - secretRef: + name: oidc-info + image: quay.io/openshiftdemos/rollouts-terminal-tooling:latest + imagePullPolicy: Always + name: oidc-token-refresher + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + serviceAccount: oidc-token-refresher + serviceAccountName: oidc-token-refresher + terminationGracePeriodSeconds: 30 diff --git a/cluster-config/components/pipelines-operator/overlays/chains/openshift-pipelines-namespace.yaml b/cluster-config/components/pipelines-operator/overlays/chains/openshift-pipelines-namespace.yaml new file mode 100644 index 0000000..50e7418 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/chains/openshift-pipelines-namespace.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipelines + kubernetes.io/metadata.name: openshift-pipelines + openshift.io/cluster-monitoring: "true" + operator.tekton.dev/disable-proxy: "true" + name: openshift-pipelines diff --git a/cluster-config/components/pipelines-operator/overlays/chains/signing-cert-external.yaml b/cluster-config/components/pipelines-operator/overlays/chains/signing-cert-external.yaml new file mode 100644 index 0000000..a969bc6 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/chains/signing-cert-external.yaml @@ -0,0 +1,16 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: signing-secrets + namespace: openshift-pipelines +spec: + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: signing-secrets + # prevent fighting with tekton over ownership + creationPolicy: Orphan + dataFrom: + - extract: + key: COSIGN diff --git a/cluster-config/components/pipelines-operator/overlays/results/kustomization.yaml b/cluster-config/components/pipelines-operator/overlays/results/kustomization.yaml new file mode 100644 index 0000000..acaadc8 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/results/kustomization.yaml @@ -0,0 +1,7 @@ +namespace: openshift-pipelines + +resources: +- pvc.yaml +- tekton-results-db-secret.yaml +- tekton-results-tls-secret.yaml +- tektonresults.yaml diff --git a/cluster-config/components/pipelines-operator/overlays/results/pvc.yaml b/cluster-config/components/pipelines-operator/overlays/results/pvc.yaml new file mode 100644 index 0000000..12301a2 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/results/pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: tekton-logs +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/cluster-config/components/pipelines-operator/overlays/results/tekton-results-db-secret.yaml b/cluster-config/components/pipelines-operator/overlays/results/tekton-results-db-secret.yaml new file mode 100644 index 0000000..71e1409 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/results/tekton-results-db-secret.yaml @@ -0,0 +1,18 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: tekton-results-postgres + namespace: openshift-pipelines +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: tekton-results-postgres + creationPolicy: Owner + dataFrom: + - extract: + key: TEKTON_RESULTS_DB diff --git a/cluster-config/components/pipelines-operator/overlays/results/tekton-results-tls-secret.yaml b/cluster-config/components/pipelines-operator/overlays/results/tekton-results-tls-secret.yaml new file mode 100644 index 0000000..baaf674 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/results/tekton-results-tls-secret.yaml @@ -0,0 +1,20 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: tekton-results-tls + namespace: openshift-pipelines +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: tekton-results-tls + creationPolicy: Owner + template: + type: kubernetes.io/tls + dataFrom: + - extract: + key: TEKTON_RESULTS_TLS diff --git a/cluster-config/components/pipelines-operator/overlays/results/tektonresults.yaml b/cluster-config/components/pipelines-operator/overlays/results/tektonresults.yaml new file mode 100644 index 0000000..3411401 --- /dev/null +++ b/cluster-config/components/pipelines-operator/overlays/results/tektonresults.yaml @@ -0,0 +1,19 @@ +apiVersion: operator.tekton.dev/v1alpha1 +kind: TektonResult +metadata: + name: result +spec: + targetNamespace: openshift-pipelines + logs_api: true + log_level: info + db_port: 5432 + db_host: tekton-results-postgres-service.openshift-pipelines.svc.cluster.local + logs_path: /logs + logs_type: File + logs_buffer_size: 32768 + auth_disable: true + tls_hostname_override: tekton-results-api-service.openshift-pipelines.svc.cluster.local + db_enable_auto_migration: true + server_port: 8080 + prometheus_port: 9090 + logging_pvc_name: tekton-logs diff --git a/cluster-config/components/rbac/base/cluster-admins-rolebinding.yaml b/cluster-config/components/rbac/base/cluster-admins-rolebinding.yaml new file mode 100644 index 0000000..5c97f73 --- /dev/null +++ b/cluster-config/components/rbac/base/cluster-admins-rolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-admin-users +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - apiGroup: rbac.authorization.k8s.io + kind: Group + name: cluster-admins diff --git a/cluster-config/components/rbac/base/kustomization.yaml b/cluster-config/components/rbac/base/kustomization.yaml new file mode 100644 index 0000000..20c61ad --- /dev/null +++ b/cluster-config/components/rbac/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- cluster-admins-rolebinding.yaml diff --git a/cluster-config/components/registry-sno/base/kustomization.yaml b/cluster-config/components/registry-sno/base/kustomization.yaml new file mode 100644 index 0000000..9f7c240 --- /dev/null +++ b/cluster-config/components/registry-sno/base/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- pvc.yaml +- registry-config.yaml diff --git a/cluster-config/components/registry-sno/base/pvc.yaml b/cluster-config/components/registry-sno/base/pvc.yaml new file mode 100644 index 0000000..7874e45 --- /dev/null +++ b/cluster-config/components/registry-sno/base/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: image-registry + namespace: openshift-image-registry +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 150Gi + storageClassName: lvms-vg1 diff --git a/cluster-config/components/registry-sno/base/registry-config.yaml b/cluster-config/components/registry-sno/base/registry-config.yaml new file mode 100644 index 0000000..7b3f908 --- /dev/null +++ b/cluster-config/components/registry-sno/base/registry-config.yaml @@ -0,0 +1,20 @@ +apiVersion: imageregistry.operator.openshift.io/v1 +kind: Config +metadata: + name: cluster +spec: + logLevel: Normal + managementState: Managed + observedConfig: null + operatorLogLevel: Normal + replicas: 1 + requests: + read: + maxWaitInQueue: 0s + write: + maxWaitInQueue: 0s + rolloutStrategy: Recreate + storage: + pvc: + claim: image-registry + unsupportedConfigOverrides: null diff --git a/cluster-config/components/rhtas-operator/instance/base/kustomization.yaml b/cluster-config/components/rhtas-operator/instance/base/kustomization.yaml new file mode 100644 index 0000000..b347a5a --- /dev/null +++ b/cluster-config/components/rhtas-operator/instance/base/kustomization.yaml @@ -0,0 +1,5 @@ +namespace: trusted-artifact-signer + +resources: +- namespace.yaml +- securesign.yaml diff --git a/cluster-config/components/rhtas-operator/instance/base/namespace.yaml b/cluster-config/components/rhtas-operator/instance/base/namespace.yaml new file mode 100644 index 0000000..4905493 --- /dev/null +++ b/cluster-config/components/rhtas-operator/instance/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/display-name: Red Hat Trusted Artifact Signer + name: trusted-artifact-signer diff --git a/cluster-config/components/rhtas-operator/instance/base/securesign.yaml b/cluster-config/components/rhtas-operator/instance/base/securesign.yaml new file mode 100644 index 0000000..ceee732 --- /dev/null +++ b/cluster-config/components/rhtas-operator/instance/base/securesign.yaml @@ -0,0 +1,57 @@ +apiVersion: rhtas.redhat.com/v1alpha1 +kind: Securesign +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "10" + labels: + app.kubernetes.io/instance: securesign + app.kubernetes.io/name: securesign + app.kubernetes.io/part-of: trusted-artifact-signer + name: securesign + namespace: trusted-artifact-signer +spec: + fulcio: + certificate: + commonName: fulcio.hostname + organizationEmail: jdoe@redhat.com + organizationName: Red Hat + config: + OIDCIssuers: + - ClientID: trusted-artifact-signer + Issuer: + IssuerURL: + Type: email + externalAccess: + enabled: true + monitoring: + enabled: false + rekor: + backFillRedis: + enabled: true + schedule: 0 0 * * * + externalAccess: + enabled: true + monitoring: + enabled: false + pvc: + retain: true + size: 5Gi + rekorSearchUI: + enabled: true + signer: + kms: secret + trillian: + database: + create: true + pvc: + retain: true + size: 5Gi + tuf: + externalAccess: + enabled: true + keys: + - name: rekor.pub + - name: ctfe.pub + - name: fulcio_v1.crt.pem + port: 80 diff --git a/cluster-config/components/rhtas-operator/operator/base/kustomization.yaml b/cluster-config/components/rhtas-operator/operator/base/kustomization.yaml new file mode 100644 index 0000000..a7ad173 --- /dev/null +++ b/cluster-config/components/rhtas-operator/operator/base/kustomization.yaml @@ -0,0 +1,6 @@ +namespace: rhtas-operator + +resources: +- namespace.yaml +- operator-group.yaml +- subscription.yaml diff --git a/cluster-config/components/rhtas-operator/operator/base/namespace.yaml b/cluster-config/components/rhtas-operator/operator/base/namespace.yaml new file mode 100644 index 0000000..4efbe69 --- /dev/null +++ b/cluster-config/components/rhtas-operator/operator/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/display-name: Red Hat Trusted Artifact Signer + name: rhtas-operator diff --git a/cluster-config/components/rhtas-operator/operator/base/operator-group.yaml b/cluster-config/components/rhtas-operator/operator/base/operator-group.yaml new file mode 100644 index 0000000..556f643 --- /dev/null +++ b/cluster-config/components/rhtas-operator/operator/base/operator-group.yaml @@ -0,0 +1,6 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: rhtas-operator +spec: + upgradeStrategy: Default diff --git a/cluster-config/components/rhtas-operator/operator/base/subscription.yaml b/cluster-config/components/rhtas-operator/operator/base/subscription.yaml new file mode 100644 index 0000000..29f1082 --- /dev/null +++ b/cluster-config/components/rhtas-operator/operator/base/subscription.yaml @@ -0,0 +1,18 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: rhtas-operator +spec: + config: + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 5m + memory: 128Mi + channel: stable-v1.1 + installPlanApproval: Automatic + name: rhtas-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/rollout-manager/base/kustomization.yaml b/cluster-config/components/rollout-manager/base/kustomization.yaml new file mode 100644 index 0000000..53e4621 --- /dev/null +++ b/cluster-config/components/rollout-manager/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- rolloutmanager.yaml diff --git a/cluster-config/components/rollout-manager/base/rolloutmanager.yaml b/cluster-config/components/rollout-manager/base/rolloutmanager.yaml new file mode 100644 index 0000000..67fcdf7 --- /dev/null +++ b/cluster-config/components/rollout-manager/base/rolloutmanager.yaml @@ -0,0 +1,6 @@ +apiVersion: argoproj.io/v1alpha1 +kind: RolloutManager +metadata: + name: cluster + namespace: openshift-gitops +spec: {} diff --git a/cluster-config/components/sso/overlays/default/keycloak-migration-job.yaml b/cluster-config/components/sso/overlays/default/keycloak-migration-job.yaml new file mode 100644 index 0000000..393636f --- /dev/null +++ b/cluster-config/components/sso/overlays/default/keycloak-migration-job.yaml @@ -0,0 +1,45 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: keycloak-migration + namespace: sso + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + template: + spec: + containers: + - image: klg71/keycloakmigration + env: + - name: BASEURL + value: "https://sso-sso.apps.home.ocplab.com/auth" + - name: CORRECT_HASHES + value: "true" + - name: ADMIN_USERNAME + valueFrom: + secretKeyRef: + name: sso-admin-credential + key: ADMIN_USERNAME + - name: ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: sso-admin-credential + key: ADMIN_PASSWORD + imagePullPolicy: Always + name: keycloak-migration + volumeMounts: + - name: keycloak-migration + mountPath: "/migration" + readOnly: true + - name: logs + mountPath: "/logs" + dnsPolicy: ClusterFirst + restartPolicy: OnFailure + terminationGracePeriodSeconds: 30 + volumes: + - name: keycloak-migration + secret: + secretName: keycloak-migration + - name: logs + emptyDir: {} diff --git a/cluster-config/components/sso/overlays/default/kustomization.yaml b/cluster-config/components/sso/overlays/default/kustomization.yaml new file mode 100644 index 0000000..f9158d4 --- /dev/null +++ b/cluster-config/components/sso/overlays/default/kustomization.yaml @@ -0,0 +1,18 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: sso + +bases: +- https://github.com/redhat-cop/gitops-catalog/rhsso/rhsso-standalone/overlays/default + +resources: +- keycloak-migration-job.yaml + +patchesJson6902: + - path: patch-sso-statefulset.yaml + target: + group: "" + kind: StatefulSet + name: sso + version: v1 diff --git a/cluster-config/components/sso/overlays/default/patch-sso-statefulset.yaml b/cluster-config/components/sso/overlays/default/patch-sso-statefulset.yaml new file mode 100644 index 0000000..a749328 --- /dev/null +++ b/cluster-config/components/sso/overlays/default/patch-sso-statefulset.yaml @@ -0,0 +1,8 @@ +- op: add + path: /spec/template/spec/containers/0/env/- + value: + name: JAVA_OPTS_APPEND + value: "-Dkeycloak.profile.feature.admin_fine_grained_authz=enabled -Dkeycloak.profile.feature.token_exchange=enabled" +- op: replace + path: /spec/template/spec/containers/0/image + value: registry.redhat.io/rh-sso-7/sso75-openshift-rhel8:latest diff --git a/cluster-config/components/tekton-hub/base/hub.yaml b/cluster-config/components/tekton-hub/base/hub.yaml new file mode 100644 index 0000000..af6eba0 --- /dev/null +++ b/cluster-config/components/tekton-hub/base/hub.yaml @@ -0,0 +1,17 @@ +apiVersion: operator.tekton.dev/v1alpha1 +kind: TektonHub +metadata: + name: hub +spec: + targetNamespace: openshift-pipelines + + catalogs: + - name: local + org: gnunn-gitops + type: community + provider: github + url: https://github.com/gnunn-gitops/tekton-catalog + revision: main + + api: + catalogRefreshInterval: 5m diff --git a/cluster-config/components/tenant-secrets/base/copy-secrets-cronjob.yaml b/cluster-config/components/tenant-secrets/base/copy-secrets-cronjob.yaml new file mode 100644 index 0000000..377b87f --- /dev/null +++ b/cluster-config/components/tenant-secrets/base/copy-secrets-cronjob.yaml @@ -0,0 +1,25 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: copy-secrets +spec: + schedule: "*/2 * * * *" + concurrencyPolicy: "Forbid" + jobTemplate: + spec: + template: + spec: + serviceAccountName: copy-secrets + containers: + - name: copy-secrets + image: quay.io/gnunn/tools:latest + imagePullPolicy: Always + command: + - /bin/bash + - -c + - | + secrets=$(oc get secrets -l replicate=true --no-headers -o custom-columns=":metadata.name") + while IFS= read -r secret; do + oc get secret $secret -o yaml | oc neat | sed "s/namespace: tenant-secrets/namespace: ${secret}/g" | oc apply -f - + done <<< "$secrets" + restartPolicy: OnFailure diff --git a/cluster-config/components/tenant-secrets/base/copy-secrets-rbac.yaml b/cluster-config/components/tenant-secrets/base/copy-secrets-rbac.yaml new file mode 100644 index 0000000..121e299 --- /dev/null +++ b/cluster-config/components/tenant-secrets/base/copy-secrets-rbac.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: copy-secrets +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: copy-secrets +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - create + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: copy-secrets +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: copy-secrets +subjects: + - kind: ServiceAccount + name: copy-secrets + namespace: tenant-secrets diff --git a/cluster-config/components/tenant-secrets/base/kustomization.yaml b/cluster-config/components/tenant-secrets/base/kustomization.yaml new file mode 100644 index 0000000..7fec527 --- /dev/null +++ b/cluster-config/components/tenant-secrets/base/kustomization.yaml @@ -0,0 +1,6 @@ +namespace: tenant-secrets + +resources: +- copy-secrets-rbac.yaml +- copy-secrets-cronjob.yaml +- namespace.yaml diff --git a/cluster-config/components/tenant-secrets/base/namespace.yaml b/cluster-config/components/tenant-secrets/base/namespace.yaml new file mode 100644 index 0000000..8b3d14f --- /dev/null +++ b/cluster-config/components/tenant-secrets/base/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/description: "manage Tenant Secrets" + name: tenant-secrets diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/bombastic-default-obc.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/bombastic-default-obc.yaml new file mode 100644 index 0000000..d411fb0 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/bombastic-default-obc.yaml @@ -0,0 +1,8 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: bombastic-default + namespace: trusted-profile-analyzer +spec: + generateBucketName: bombastic-default + storageClassName: openshift-storage.noobaa.io diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/bombastic-topics.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/bombastic-topics.yaml new file mode 100644 index 0000000..f21dfe1 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/bombastic-topics.yaml @@ -0,0 +1,41 @@ +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: bombastic-failed-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 +--- +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: bombastic-indexed-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 +--- +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: bombastic-stored-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/kafka.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/kafka.yaml new file mode 100644 index 0000000..77fc1b4 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/kafka.yaml @@ -0,0 +1,35 @@ +apiVersion: kafka.strimzi.io/v1beta2 +kind: Kafka +metadata: + name: kafka + namespace: trusted-profile-analyzer +spec: + entityOperator: + topicOperator: {} + kafka: + config: + default.replication.factor: 1 + inter.broker.protocol.version: "3.7" + min.insync.replicas: 1 + offsets.topic.replication.factor: 1 + transaction.state.log.min.isr: 1 + transaction.state.log.replication.factor: 1 + listeners: + - name: plain + port: 9092 + tls: false + type: internal + - name: tls + port: 9093 + tls: true + type: internal + replicas: 1 + storage: + type: persistent-claim + size: 1Gi + version: 3.7.0 + zookeeper: + replicas: 1 + storage: + type: persistent-claim + size: 1Gi diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/kustomization.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/kustomization.yaml new file mode 100644 index 0000000..f29ea30 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/kustomization.yaml @@ -0,0 +1,15 @@ +namespace: trusted-profile-analyzer + +resources: +- namespace.yaml +- vexination-default-obc.yaml +- v11y-default-obc.yaml +- bombastic-default-obc.yaml +- kafka.yaml +- v11y-topics.yaml +- bombastic-topics.yaml +- vexination-topics.yaml +- postgresql-pvc.yaml +- postgresql-es.yaml +- postgresql-deploy.yaml +- postgresql-svc.yaml diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/namespace.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/namespace.yaml new file mode 100644 index 0000000..ca4a48d --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: trusted-profile-analyzer diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-deploy.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-deploy.yaml new file mode 100644 index 0000000..a2f6847 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-deploy.yaml @@ -0,0 +1,80 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + argocd.argoproj.io/sync-wave: "1" + name: postgresql + namespace: trusted-profile-analyzer +spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + name: postgresql + strategy: + type: Recreate + template: + metadata: + labels: + name: postgresql + spec: + containers: + - env: + - name: POSTGRESQL_USER + valueFrom: + secretKeyRef: + key: database-user + name: postgresql + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + key: database-password + name: postgresql + - name: POSTGRESQL_DATABASE + valueFrom: + secretKeyRef: + key: database-name + name: postgresql + image: image-registry.openshift-image-registry.svc:5000/openshift/postgresql:15-el8 + imagePullPolicy: IfNotPresent + livenessProbe: + exec: + command: + - /usr/libexec/check-container + - --live + failureThreshold: 3 + initialDelaySeconds: 120 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 10 + name: postgresql + ports: + - containerPort: 5432 + protocol: TCP + readinessProbe: + exec: + command: + - /usr/libexec/check-container + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + memory: 512Mi + securityContext: + privileged: false + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /var/lib/pgsql/data + name: postgresql-data + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + terminationGracePeriodSeconds: 30 + volumes: + - name: postgresql-data + persistentVolumeClaim: + claimName: postgresql diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-es.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-es.yaml new file mode 100644 index 0000000..34a0d82 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-es.yaml @@ -0,0 +1,18 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-wave: "0" + name: postgresql + namespace: trusted-profile-analyzer +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: doppler-cluster + target: + name: postgresql + creationPolicy: Owner + dataFrom: + - extract: + key: RHTPA_POSTGRESQL diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-pvc.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-pvc.yaml new file mode 100644 index 0000000..ba08b12 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgresql + namespace: trusted-profile-analyzer +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-svc.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-svc.yaml new file mode 100644 index 0000000..6450228 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/postgresql-svc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: postgresql + namespace: trusted-profile-analyzer +spec: + ports: + - name: postgresql + port: 5432 + selector: + name: postgresql diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/v11y-default-obc.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/v11y-default-obc.yaml new file mode 100644 index 0000000..999e32c --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/v11y-default-obc.yaml @@ -0,0 +1,8 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: v11y-default + namespace: trusted-profile-analyzer +spec: + generateBucketName: v11y-default + storageClassName: openshift-storage.noobaa.io diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/v11y-topics.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/v11y-topics.yaml new file mode 100644 index 0000000..a167978 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/v11y-topics.yaml @@ -0,0 +1,41 @@ +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: v11y-failed-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 +--- +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: v11y-indexed-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 +--- +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: v11y-stored-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/vexination-default-obc.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/vexination-default-obc.yaml new file mode 100644 index 0000000..158655b --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/vexination-default-obc.yaml @@ -0,0 +1,8 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: vexination-default + namespace: trusted-profile-analyzer +spec: + generateBucketName: vexination-default + storageClassName: openshift-storage.noobaa.io diff --git a/cluster-config/components/trusted-profile-analyzer/prereqs/base/vexination-topics.yaml b/cluster-config/components/trusted-profile-analyzer/prereqs/base/vexination-topics.yaml new file mode 100644 index 0000000..8be41e4 --- /dev/null +++ b/cluster-config/components/trusted-profile-analyzer/prereqs/base/vexination-topics.yaml @@ -0,0 +1,41 @@ +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: vexination-failed-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 +--- +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: vexination-indexed-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 +--- +kind: KafkaTopic +apiVersion: kafka.strimzi.io/v1beta2 +metadata: + name: vexination-stored-default + labels: + strimzi.io/cluster: kafka + namespace: trusted-profile-analyzer +spec: + partitions: 10 + replicas: 1 + config: + retention.ms: 604800000 + segment.bytes: 1073741824 diff --git a/cluster-config/components/wake-on-lan/base/kustomization.yaml b/cluster-config/components/wake-on-lan/base/kustomization.yaml new file mode 100644 index 0000000..e24f5b7 --- /dev/null +++ b/cluster-config/components/wake-on-lan/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- wake-on-lan-mc.yaml diff --git a/cluster-config/components/wake-on-lan/base/wake-on-lan-mc.yaml b/cluster-config/components/wake-on-lan/base/wake-on-lan-mc.yaml new file mode 100644 index 0000000..6d7f76d --- /dev/null +++ b/cluster-config/components/wake-on-lan/base/wake-on-lan-mc.yaml @@ -0,0 +1,21 @@ +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + name: 99-wol-service + labels: + kubernetes.io/os: linux +spec: + config: + ignition: + version: 3.2.0 + systemd: + units: + - enabled: true + name: wol@.service + storage: + files: + - contents: + source: data:text/plain;charset=utf-8;base64,W1VuaXRdCkRlc2NyaXB0aW9uPVdha2Utb24tTEFOIGZvciAlaQpSZXF1aXJlcz1uZXR3b3JrLnRhcmdldApBZnRlcj1uZXR3b3JrLnRhcmdldAoKW1NlcnZpY2VdCkV4ZWNTdGFydD0vdXNyL3NiaW4vZXRodG9vbCAtcyAlaSB3b2wgZwpUeXBlPW9uZXNob3QKCltJbnN0YWxsXQpXYW50ZWRCeT1tdWx0aS11c2VyLnRhcmdldA== + mode: 0644 + overwrite: true + path: /etc/systemd/system/wol@.service diff --git a/cluster-config/components/wake-on-lan/base/wol.service b/cluster-config/components/wake-on-lan/base/wol.service new file mode 100644 index 0000000..c5c820a --- /dev/null +++ b/cluster-config/components/wake-on-lan/base/wol.service @@ -0,0 +1,11 @@ +[Unit] +Description=Wake-on-LAN for %i +Requires=network.target +After=network.target + +[Service] +ExecStart=/usr/sbin/ethtool -s %i wol g +Type=oneshot + +[Install] +WantedBy=multi-user.target diff --git a/cluster-config/components/web-terminal-operator/base/kustomization.yaml b/cluster-config/components/web-terminal-operator/base/kustomization.yaml new file mode 100644 index 0000000..9ad12ad --- /dev/null +++ b/cluster-config/components/web-terminal-operator/base/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- subscription.yaml diff --git a/cluster-config/components/web-terminal-operator/base/subscription.yaml b/cluster-config/components/web-terminal-operator/base/subscription.yaml new file mode 100644 index 0000000..be7e58b --- /dev/null +++ b/cluster-config/components/web-terminal-operator/base/subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: web-terminal + namespace: openshift-operators +spec: + channel: fast + installPlanApproval: Automatic + name: web-terminal + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/cluster-config/components/worker-node-config/base/kubeletconfig.yaml b/cluster-config/components/worker-node-config/base/kubeletconfig.yaml new file mode 100644 index 0000000..6c8b963 --- /dev/null +++ b/cluster-config/components/worker-node-config/base/kubeletconfig.yaml @@ -0,0 +1,11 @@ +apiVersion: machineconfiguration.openshift.io/v1 +kind: KubeletConfig +metadata: + name: custom-worker-config +spec: + autoSizingReserved: true + machineConfigPoolSelector: + matchLabels: + custom-kubelet: custom-worker-config + kubeletConfig: + maxPods: 350 diff --git a/cluster-config/docs/img/argocd-logo.png b/cluster-config/docs/img/argocd-logo.png new file mode 100644 index 0000000..e204697 Binary files /dev/null and b/cluster-config/docs/img/argocd-logo.png differ diff --git a/cluster-config/docs/img/argocd.png b/cluster-config/docs/img/argocd.png new file mode 100644 index 0000000..e309bbb Binary files /dev/null and b/cluster-config/docs/img/argocd.png differ diff --git a/cluster-config/docs/index.html b/cluster-config/docs/index.html new file mode 100644 index 0000000..8c2a964 --- /dev/null +++ b/cluster-config/docs/index.html @@ -0,0 +1,8 @@ + + + Hosted CSS themes for Argo CD + + +

Nothing to see here, move along... + + diff --git a/cluster-config/docs/themes/aws.cluster/custom-cluster.css b/cluster-config/docs/themes/aws.cluster/custom-cluster.css new file mode 100644 index 0000000..c9bafe7 --- /dev/null +++ b/cluster-config/docs/themes/aws.cluster/custom-cluster.css @@ -0,0 +1,14 @@ +div.columns.small-9.top-bar__left-side { + background: #fefefe; +} +div.columns.top-bar__left-side, +div.top-bar__title.text-truncate.top-bar__right-side { + background: #FF9900; + color: #252F3E; +} +.top-bar__breadcrumbs { + color: #252F3E !important; +} +.top-bar__title { + color: #252F3E !important; +} diff --git a/cluster-config/docs/themes/local.home/custom-cluster.css b/cluster-config/docs/themes/local.home/custom-cluster.css new file mode 100644 index 0000000..8a4eff3 --- /dev/null +++ b/cluster-config/docs/themes/local.home/custom-cluster.css @@ -0,0 +1,14 @@ +div.columns.small-9.top-bar__left-side { + background: #fefefe; +} +div.columns.top-bar__left-side, +div.top-bar__title.text-truncate.top-bar__right-side { + background: #0066CC; + color: #fff; +} +.top-bar__breadcrumbs { + color: #fff !important; +} +.top-bar__title { + color: #fff !important; +} diff --git a/cluster-config/docs/themes/local.hub/custom-cluster.css b/cluster-config/docs/themes/local.hub/custom-cluster.css new file mode 100644 index 0000000..139a2f6 --- /dev/null +++ b/cluster-config/docs/themes/local.hub/custom-cluster.css @@ -0,0 +1,14 @@ +div.columns.small-9.top-bar__left-side { + background: #fefefe; +} +div.columns.top-bar__left-side, +div.top-bar__title.text-truncate.top-bar__right-side { + background: #3E8635; + color: #fff; +} +.top-bar__breadcrumbs { + color: #fff !important; +} +.top-bar__title { + color: #fff !important; +} diff --git a/cluster-config/docs/themes/rhdp/custom-cluster.css b/cluster-config/docs/themes/rhdp/custom-cluster.css new file mode 100644 index 0000000..d3c23af --- /dev/null +++ b/cluster-config/docs/themes/rhdp/custom-cluster.css @@ -0,0 +1,14 @@ +div.columns.small-9.top-bar__left-side { + background: #fefefe; +} +div.columns.top-bar__left-side, +div.top-bar__title.text-truncate.top-bar__right-side { + background: #EE0000; + color: #fff; +} +.top-bar__breadcrumbs { + color: #fff !important; +} +.top-bar__title { + color: #fff !important; +} diff --git a/cluster-config/scripts/validate_manifests.sh b/cluster-config/scripts/validate_manifests.sh new file mode 100755 index 0000000..de7d363 --- /dev/null +++ b/cluster-config/scripts/validate_manifests.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# shellcheck disable=SC2034,SC2044 + +# DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +DIR="$(pwd)" + +function display_help { + echo "./$(basename "$0") [ -d | --directory DIRECTORY ] [ -q | --quiet ] [ -h | --help | --vpc-keypair | --lab | --teardown | --redeploy | --clear-logs ] [ OPTIONAL ANSIBLE OPTIONS ] +Script to validate the manifests generated by Kustomize +Where: + -d | --directory DIRECTORY Base directory containing Kustomize overlays + -e | --enforce-all-schemas Enable enforcement of all schemas + -h | --help Display this help text + -sl | --schema-location Location containing schemas" +} + +which kustomize && KUSTOMIZE_CMD="kustomize build" + +KUSTOMIZE_CMD="${KUSTOMIZE_CMD:-oc kustomize}" +KUSTOMIZE_OPTIONS="--enable-helm" +IGNORE_MISSING_SCHEMAS="--ignore-missing-schemas" +SCHEMA_LOCATION="${DIR}/openshift-json-schema" +KUSTOMIZE_DIRS="${DIR}" +ERROR_COLOR='\033[0;31m' +NO_COLOR='\033[0m' + +for i in "$@" +do + case $i in + -d=* | --directory=* ) + KUSTOMIZE_DIRS="${i#*=}" + shift + ;; + -e | --enforce-all-schemas ) + shift + IGNORE_MISSING_SCHEMAS="" + shift + ;; + -sl=* | --schema-location=* ) + SCHEMA_LOCATION="${i#*=}" + shift + ;; + -h | --help ) + display_help + exit 0 + ;; + esac +done + +errors=0 + +for i in $(find "${KUSTOMIZE_DIRS}" -name "kustomization.yaml" -exec dirname {} \;) +do + echo + echo "Validating $i" + echo + + if [ -f "$i/.skip_validation" ]; then + echo "Skipping validation due to .skip_validation marker file" + continue + fi + + KUSTOMIZE_BUILD_OUTPUT=$(${KUSTOMIZE_CMD} "$i" $KUSTOMIZE_OPTIONS) + + build_response=$? + + if [ $build_response -ne 0 ]; then + >&2 echo -e "${ERROR_COLOR}Error building $i${NO_COLOR}" + errors=$((errors + 1)) + fi + +# echo "$KUSTOMIZE_BUILD_OUTPUT" | kubeval ${IGNORE_MISSING_SCHEMAS} --schema-location="file://${SCHEMA_LOCATION}" --force-color + +# validation_response=$? + +# if [ $validation_response -ne 0 ]; then +# echo "Error validating $i" +# exit 1 +# fi +done + +echo +if [ $errors -ne 0 ]; then + echo -e "${ERROR_COLOR}$errors Errors occurred, see logs${NO_COLOR}" + exit 1 +else + echo "Manifests successfully validated!" +fi diff --git a/cluster-config/tenants/README.md b/cluster-config/tenants/README.md new file mode 100644 index 0000000..d2fa09d --- /dev/null +++ b/cluster-config/tenants/README.md @@ -0,0 +1 @@ +WIP, changing to new system diff --git a/cluster-config/tenants/product-catalog/base/github-pipeline-scc-rolebinding.yaml b/cluster-config/tenants/product-catalog/base/github-pipeline-scc-rolebinding.yaml new file mode 100644 index 0000000..c571a91 --- /dev/null +++ b/cluster-config/tenants/product-catalog/base/github-pipeline-scc-rolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: github-pipeline-scc-rolebinding + namespace: product-catalog-cicd +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pipelines-scc-clusterrole +subjects: +- kind: ServiceAccount + name: github-pipeline diff --git a/cluster-config/tenants/product-catalog/base/kustomization.yaml b/cluster-config/tenants/product-catalog/base/kustomization.yaml new file mode 100644 index 0000000..9257a79 --- /dev/null +++ b/cluster-config/tenants/product-catalog/base/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: tenant + version: 0.3.4 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: gitops + releaseName: product-catalog + +resources: +- ./monitor +- github-pipeline-scc-rolebinding.yaml diff --git a/cluster-config/tenants/product-catalog/base/monitor/kustomization.yaml b/cluster-config/tenants/product-catalog/base/monitor/kustomization.yaml new file mode 100644 index 0000000..04f4c06 --- /dev/null +++ b/cluster-config/tenants/product-catalog/base/monitor/kustomization.yaml @@ -0,0 +1,38 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: product-catalog-monitor + +resources: +- https://github.com/gnunn1/gitops-catalog/grafana-operator/overlays/user-app +#- github.com/redhat-cop/gitops-catalog/grafana-operator/overlays/user-app + +# Patch in namespace for Argo CD that is managing this namespace +patches: +- patch: |- + - op: add + path: /spec/config/users + value: + default_theme: light + target: + kind: Grafana + name: grafana +- patch: |- + - op: add + path: /subjects/0/namespace + value: product-catalog-monitor + - op: replace + path: /metadata/name + value: cluster-monitoring-view-product-catalog-monitor + target: + group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: cluster-monitoring-view +- patch: |- + - op: add + path: /subjects/0/namespace + value: product-catalog-monitor + target: + group: rbac.authorization.k8s.io + kind: RoleBinding + name: grafana-proxy diff --git a/cluster-config/tenants/product-catalog/base/values.yaml b/cluster-config/tenants/product-catalog/base/values.yaml new file mode 100644 index 0000000..6a69412 --- /dev/null +++ b/cluster-config/tenants/product-catalog/base/values.yaml @@ -0,0 +1,71 @@ +tenant: product-catalog + +default: + argocd: + cluster: + name: in-cluster + annotations: + app.openshift.io/vcs-uri: https://github.com/gnunn-gitops/product-catalog + app.openshift.io/vcs-ref: main + labels: + argocd.argoproj.io/managed-by: gitops + tenant: product-catalog + networkPolicy: true + rbac: + adminGroups: + - product-catalog-admins + editGroups: + - product-catalog-users + +argocd: + namespace: gitops + sourceRepos: + - '*' + adminGroups: + - product-catalog-admins + userGroups: + - product-catalog-users + pipelineGroups: + - product-catalog-pipeline + +externalSecrets: + tenantClusterSecretStore: doppler-cluster + tenantSecretNamespace: tenant-secrets + +namespaces: + + dev: + quota: medium + annotations: + openshift.io/description: Project for development environment of product catalog application + openshift.io/display-name: Product Catalog Development + + test: + quota: medium + annotations: + openshift.io/description: Project for test environment of product catalog application + openshift.io/display-name: Product Catalog Test + + prod: + quota: medium + annotations: + openshift.io/description: Project for production environment of product catalog application + openshift.io/display-name: Product Catalog Prod + + cicd: + externalSecrets: + tenantTokenKey: TENANT_PRODUCT_CATALOG_DOPPLER_TOKEN + annotations: + openshift.io/description: Project for ci/cd tools for product catalog application + openshift.io/display-name: Product Catalog CI/CD + + gitops: + annotations: + openshift.io/description: Project for gitops tool for product catalog team + openshift.io/display-name: Product Catalog GitOps + + monitor: + annotations: + openshift.io/description: Project for monitoring tools of product catalog application + openshift.io/display-name: Product Catalog Monitor + operatorGroup: true diff --git a/cluster-config/tenants/rollouts-demo/base/analysis-auth-monitoring.yaml b/cluster-config/tenants/rollouts-demo/base/analysis-auth-monitoring.yaml new file mode 100644 index 0000000..b727ea7 --- /dev/null +++ b/cluster-config/tenants/rollouts-demo/base/analysis-auth-monitoring.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: analysis-monitoring-view + namespace: rollouts-demo-prod +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-monitoring-view +subjects: + - kind: ServiceAccount + name: default + namespace: rollouts-demo-prod diff --git a/cluster-config/tenants/rollouts-demo/base/kustomization.yaml b/cluster-config/tenants/rollouts-demo/base/kustomization.yaml new file mode 100644 index 0000000..d1a0cdc --- /dev/null +++ b/cluster-config/tenants/rollouts-demo/base/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: tenant + version: 0.3.4 + repo: https://gnunn-gitops.github.io/helm-charts + valuesFile: values.yaml + namespace: gitops + releaseName: product-catalog + +resources: +- analysis-auth-monitoring.yaml diff --git a/cluster-config/tenants/rollouts-demo/base/values.yaml b/cluster-config/tenants/rollouts-demo/base/values.yaml new file mode 100644 index 0000000..4e1a055 --- /dev/null +++ b/cluster-config/tenants/rollouts-demo/base/values.yaml @@ -0,0 +1,54 @@ +tenant: rollouts-demo + +default: + argocd: + cluster: + name: in-cluster + labels: + argocd.argoproj.io/managed-by: gitops + tenant: rollouts-demo + networkPolicy: true + rbac: + adminGroups: + - rollouts-demo-admins + editGroups: + - rollouts-demo-users + +argocd: + namespace: gitops + sourceRepos: + - '*' + adminGroups: + - rollouts-demo-admins + userGroups: + - rollouts-demo-users + pipelineGroups: + - rollouts-demo-pipeline + +externalSecrets: + tenantClusterSecretStore: doppler-cluster + tenantSecretNamespace: tenant-secrets + +namespaces: + + dev: + annotations: + openshift.io/description: Project for dev environment of rollouts demo application + openshift.io/display-name: Rollouts Demo Development + + prod: + annotations: + openshift.io/description: Project for prod environment of rollouts demo application + openshift.io/display-name: Rollouts Demo Production + + cicd: + externalSecrets: + tenantTokenKey: TENANT_ROLLOUTS_DEMO_DOPPLER_TOKEN + annotations: + openshift.io/description: Project for ci/cd tools for rollouts demo application + openshift.io/display-name: Rollouts Demo CI/CD + + gitops: + annotations: + openshift.io/description: Project for gitops tool for rollouts demo team + openshift.io/display-name: Rollouts Demo GitOps