Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion argocd/argocd/argocd/values.ftl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ argo-cd:
# Unfortunately, as of argocd 2.6 this leads to failing notifications
# https://github.com/argoproj/argo-cd/issues/11252
params:
application.namespaces: "*"
application.namespaces: "${config.application.namePrefix}argocd"
server.insecure: true # tls terminated in ingress

# Repo credential templates are created dynamically in groovy, so they are not stored in git
Expand Down
4 changes: 3 additions & 1 deletion argocd/argocd/operator/argocd.ftl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ spec:
- name: bitnami
type: helm
url: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
<#if !config.application.clusterAdmin>
resourceInclusions: |
- apiGroups:
- "batch"
Expand Down Expand Up @@ -250,4 +251,5 @@ spec:
- "Probe"
clusters:
- "https://kubernetes.default.svc"
- "${config.features.argocd.resourceInclusionsCluster}"
- "${config.features.argocd.resourceInclusionsCluster}"
</#if>
8 changes: 8 additions & 0 deletions docs/configuration.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
"type" : [ "string", "null" ],
"description" : "the external base url (TLD) for all tools, e.g. https://example.com or http://localhost:8080. The individual -url params for argocd, grafana, vault and mailhog take precedence."
},
"clusterAdmin" : {
"type" : [ "boolean", "null" ],
"description" : "Binds ArgoCD controllers to cluster-admin ClusterRole"
},
"destroy" : {
"type" : [ "boolean", "null" ],
"description" : "Unroll playground"
Expand Down Expand Up @@ -132,6 +136,10 @@
"type" : [ "boolean", "null" ],
"description" : "Deploy example content: source repos, GitOps repos, Jenkins Job, Argo CD apps/project"
},
"multitenancyExamples" : {
"type" : [ "boolean", "null" ],
"description" : "Deploy multi tenancy example content: source repos, GitOps repos, Jenkins Job, Argo CD apps/project"
},
"namespaces" : {
"description" : "Additional kubernetes namespaces. These are authorized to Argo CD, supplied with image pull secrets, monitored by prometheus, etc. Namespaces can be templates, e.g. ${config.application.namePrefix}staging",
"type" : [ "array", "null" ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ metadata:
name: example-apps
namespace: ${config.application.namePrefix}argocd
annotations:
<#if config.features.mail.active?? && config.features.mail.active>
notifications.argoproj.io/subscribe.email: ${config.features.argocd.emailToUser}
</#if>
spec:
description: Contains examples of end-user applications
destinations:
Expand All @@ -21,11 +18,9 @@ spec:

# allow to only see application resources from the specified namespace
sourceNamespaces:
- '${config.application.namePrefix}example-apps-staging'
- '${config.application.namePrefix}example-apps-production'
<#if config.features.argocd.operator>
- '${config.application.namePrefix}argocd'
</#if>
- ${config.application.namePrefix}example-apps-staging
- ${config.application.namePrefix}example-apps-production
- ${config.application.namePrefix}argocd


# Allow all namespaced-scoped resources to be created
Expand All @@ -34,4 +29,4 @@ spec:
kind: '*'

# Deny all cluster-scoped resources from being created. Least privilege.
clusterResourceWhitelist:
clusterResourceWhitelist:

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion examples/example-apps-via-content-loader/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ content:
yamllint: "cytopia/yamllint:1.25-0.7"
nginx: ""
petclinic: "eclipse-temurin:17-jre-alpine"
maven: ""
maven: ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: gop-multi-tenancy
namespace: ${config.application.namePrefix}argocd
spec:
goTemplate: true
goTemplateOptions:
- missingkey=error
generators:
- git:
repoURL: ${scm.repoUrl}argocd/tenant-configs.git
revision: HEAD
files:
- path: "tenants/*/config.yaml"
template:
metadata:
name: gop-tenant-{{.config.application.namePrefix}}
spec:
project: argocd
sources:
- repoURL: ${scm.repoUrl}argocd/tenant-configs.git
targetRevision: HEAD
ref: valuesRef
- repoURL: ${scm.repoUrl}3rd-party-dependencies/gop-helm.git
path: .
targetRevision: HEAD
helm:
valueFiles:
- $valuesRef/tenants/globalValues.yaml
- $valuesRef/{{ .path.path }}/config.yaml
destination:
server: https://kubernetes.default.svc
namespace: ${config.application.namePrefix}argocd
syncPolicy:
automated:
selfHeal: true
prune: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
image:
tag: latest
config:
application:
baseUrl: "http://localhost"
insecure: true
username: "admin"
password: "admin"
namePrefix: ""
namespaceIsolation: true
skipCrds: true
jenkins:
active: true
features:
monitoring:
active: false
argocd:
active: true
operator: true
env: [ ]
resourceInclusionsCluster: "https://10.43.0.1:443"
ingressNginx:
active: false
multiTenant:
useDedicatedInstance: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
config:
application:
baseUrl: "http://tenant1.localhost"
namePrefix: "tenant1"
registry:
active: true
content:
examples: true
38 changes: 38 additions & 0 deletions examples/init-multi-tenancy/managementConfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
application:
baseUrl: "http://localhost"
insecure: true
username: "admin"
password: "admin"
"yes": true
namePrefix: ""
namespaceIsolation: false
skipCrds: true
clusterAdmin: true
jenkins:
active: false
features:
monitoring:
active: false
argocd:
active: true
operator: false
env: []
resourceInclusionsCluster: "https://10.43.0.1:443"
ingressNginx:
active: true
content:
repos:
- url: https://github.com/cloudogu/gop-helm
target: 3rd-party-dependencies/gop-helm
overwriteMode: RESET
- url: https://github.com/cloudogu/gitops-playground
# - url: file:///home/cl-pc-0087/src/gitops-playground
path: examples/init-multi-tenancy
ref: feature/init-multi-tenancy
templating: true
type: FOLDER_BASED
overwriteMode: UPGRADE

namespaces:
- tenant1-argocd
variables:
12 changes: 10 additions & 2 deletions src/main/groovy/com/cloudogu/gitops/cli/GitopsPlaygroundCli.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,12 @@ class GitopsPlaygroundCli {
String configFilePath = cliParams.application.configFile
String configMapName = cliParams.application.configMap
Boolean contentExamples = cliParams.content.examples
Boolean multiTenancyExamples = cliParams.content.multitenancyExamples

Map configFile = [:]
Map configMap = [:]
Map contentExamplesFile = [:]
Map multiTenancyContentExamplesFile = [:]

if (configFilePath) {
log.debug("Reading config file ${configFilePath}")
Expand All @@ -205,14 +207,20 @@ class GitopsPlaygroundCli {
configMap = validateConfig(configValues)
}

if(contentExamples) {
if (contentExamples) {
String contentExamplesConfigPath = "examples/example-apps-via-content-loader/config.yaml"
log.debug("Adding example-apps-via-content-loader configuration from '${contentExamplesConfigPath}'")
contentExamplesFile = validateConfig(new File(contentExamplesConfigPath).text)
}

if (multiTenancyExamples) {
String multiTenancyContentExamplesConfigPath = "examples/init-multi-tenancy/managementConfig.yaml"
log.debug("Adding multi tenancy example-apps config loader from '${multiTenancyContentExamplesConfigPath}'")
multiTenancyContentExamplesFile = validateConfig(new File(multiTenancyContentExamplesConfigPath).text)
}

// Last one takes precedence
def configPrecedence = [configMap, configFile, contentExamplesFile]
def configPrecedence = [configMap, configFile, contentExamplesFile, multiTenancyContentExamplesFile]
Map mergedConfigs = [:]
configPrecedence.each {
deepMerge(it, mergedConfigs)
Expand Down
8 changes: 8 additions & 0 deletions src/main/groovy/com/cloudogu/gitops/config/Config.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ class Config {
@JsonPropertyDescription(CONTENT_EXAMPLES_DESCRIPTION)
Boolean examples = false

@Option(names = ['--multi-tenancy-examples'], description = CONTENT_MULTI_TENANCY_EXAMPLES_DESCRIPTION)
@JsonPropertyDescription(CONTENT_MULTI_TENANCY_EXAMPLES_DESCRIPTION)
Boolean multitenancyExamples = false

@JsonPropertyDescription(CONTENT_NAMESPACES_DESCRIPTION)
List<String> namespaces = []

Expand Down Expand Up @@ -399,6 +403,10 @@ class Config {
@JsonPropertyDescription(NETPOLS_DESCRIPTION)
Boolean netpols = false

@Option(names = ['--cluster-admin'], description = CLUSTER_ADMIN_DESCRIPTION)
@JsonPropertyDescription(CLUSTER_ADMIN_DESCRIPTION)
Boolean clusterAdmin = false

static class NamespaceSchema {
LinkedHashSet<String> dedicatedNamespaces = new LinkedHashSet<>()
LinkedHashSet<String> tenantNamespaces = new LinkedHashSet<>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ interface ConfigConstants {

// ContentLoader
String CONTENT_EXAMPLES_DESCRIPTION = 'Deploy example content: source repos, GitOps repos, Jenkins Job, Argo CD apps/project'
String CONTENT_MULTI_TENANCY_EXAMPLES_DESCRIPTION = "Deploy multi tenancy example content: source repos, GitOps repos, Jenkins Job, Argo CD apps/project"

String CONTENT_NAMESPACES_DESCRIPTION = 'Additional kubernetes namespaces. These are authorized to Argo CD, supplied with image pull secrets, monitored by prometheus, etc. Namespaces can be templates, e.g. ${config.application.namePrefix}staging'
String CONTENT_REPO_DESCRIPTION = "ContentLoader repos to push into target environment"
String CONTENT_REPO_URL_DESCRIPTION = "URL of the content repo. Mandatory for each type."
Expand Down Expand Up @@ -88,6 +90,7 @@ interface ConfigConstants {
String NAMESPACE_ISOLATION_DESCRIPTION = 'Configure tools to explicitly work with the given namespaces only, and not cluster-wide. This way GOP can be installed without having cluster-admin permissions.'
String MIRROR_REPOS_DESCRIPTION = 'Changes the sources of deployed tools so they are not pulled from the internet, but are pulled from git and work in air-gapped environments.'
String NETPOLS_DESCRIPTION = 'Sets Network Policies'
String CLUSTER_ADMIN_DESCRIPTION = 'Binds ArgoCD controllers to cluster-admin ClusterRole'
String OPENSHIFT_DESCRIPTION = 'When set, openshift specific resources and configurations are applied'

// group metrics
Expand Down
14 changes: 14 additions & 0 deletions src/main/groovy/com/cloudogu/gitops/features/argocd/ArgoCD.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,20 @@ class ArgoCD extends Feature {
.withSubfolder(OPERATOR_RBAC_PATH)
.generate()
}

if(config.application.clusterAdmin) {
new RbacDefinition(Role.Variant.CLUSTER_ADMIN)
.withName("argocd-cluster-admin")
.withNamespace(namespace)
.withServiceAccountsFrom(
namespace,
["argocd-argocd-server", "argocd-argocd-application-controller", "argocd-applicationset-controller"]
)
.withConfig(config)
.withRepo(argocdRepoInitializationAction.repo)
.withSubfolder(OPERATOR_RBAC_PATH)
.generate()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,37 @@ class RbacDefinition {
throw new IllegalStateException("SCMM repo must be set using withRepo() before calling generate()")
}

def role = new Role(name, namespace, variant, config)
def binding = new RoleBinding(name, namespace, name, serviceAccounts)

log.trace("Generating RBAC for name='${name}', namespace='${namespace}', subfolder='${subfolder}'")

def outputDir = Path.of(repo.absoluteLocalRepoTmpDir, subfolder).toFile()
File outputDir = Path.of(repo.absoluteLocalRepoTmpDir, subfolder).toFile()
outputDir.mkdirs()

generateRole(outputDir)

generateRoleBinding(outputDir)
}

private void generateRole(File outputDir) {
if(variant == Role.Variant.CLUSTER_ADMIN) {
log.trace("Skipping creation of ClusterRole cluster-admin")
return
}

def role = new Role(name, namespace, variant, config)

templater.template(
role.getTemplateFile(),
role.getOutputFile(outputDir),
role.toTemplateParams()
)
}

private void generateRoleBinding(File outputDir) {
String roleName = name
if(variant == Role.Variant.CLUSTER_ADMIN) {
roleName = "cluster-admin"
}
def binding = new RoleBinding(name, namespace, roleName, serviceAccounts)

templater.template(
binding.getTemplateFile(),
Expand Down
Loading