Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tls cert mount appset controller #985

Merged
Show file tree
Hide file tree
Changes from 3 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: 2 additions & 0 deletions api/v1beta1/argocd_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ type ArgoCDApplicationSet struct {
LogLevel string `json:"logLevel,omitempty"`

WebhookServer WebhookServerSpec `json:"webhookServer,omitempty"`

ScmRootCaPath string `json:"scmRootCaPath,omitempty"`
ishitasequeira marked this conversation as resolved.
Show resolved Hide resolved
}

// ArgoCDCASpec defines the CA options for ArgCD.
Expand Down
2 changes: 2 additions & 0 deletions bundle/manifests/argoproj.io_argocds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6653,6 +6653,8 @@ spec:
to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
type: object
scmRootCaPath:
type: string
version:
description: Version is the Argo CD ApplicationSet image tag.
(optional)
Expand Down
3 changes: 3 additions & 0 deletions common/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ const (
// ArgoCDTLSCertsConfigMapName is the upstream hard-coded TLS certificate data ConfigMap name.
ArgoCDTLSCertsConfigMapName = "argocd-tls-certs-cm"

// ArgoCDAppSetGitlabSCMTLSCertsConfigMapName is the hard-coded ApplicationSet Gitlab SCM TLS certificate data ConfigMap name.
ArgoCDAppSetGitlabSCMTLSCertsConfigMapName = "argocd-appset-gitlab-scm-tls-certs-cm"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason for going with config map and not a secret ?

Copy link
Collaborator Author

@ishitasequeira ishitasequeira Sep 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No specific reason, followed what we have used for TLS certs.


// ArgoCDRedisServerTLSSecretName is the name of the TLS secret for the redis-server
ArgoCDRedisServerTLSSecretName = "argocd-operator-redis-tls"

Expand Down
2 changes: 2 additions & 0 deletions config/crd/bases/argoproj.io_argocds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6644,6 +6644,8 @@ spec:
to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
type: object
scmRootCaPath:
type: string
version:
description: Version is the Argo CD ApplicationSet image tag.
(optional)
Expand Down
35 changes: 32 additions & 3 deletions controllers/argocd/applicationset.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func getArgoApplicationSetCommand(cr *argoproj.ArgoCD) []string {
cmd = append(cmd, "--loglevel")
cmd = append(cmd, getLogLevel(cr.Spec.ApplicationSet.LogLevel))

if cr.Spec.ApplicationSet.ScmRootCaPath != "" {
cmd = append(cmd, "--scm-root-ca-path")
cmd = append(cmd, cr.Spec.ApplicationSet.ScmRootCaPath)
}

// ApplicationSet command arguments provided by the user
extraArgs := cr.Spec.ApplicationSet.ExtraCommandArgs
err := isMergable(extraArgs, cmd)
Expand Down Expand Up @@ -144,9 +149,26 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD,
},
},
}
addSCMGitlabVolumeMount := false
if cr.Spec.ApplicationSet.ScmRootCaPath != "" {
cm := newConfigMapWithName(getCAConfigMapName(cr), cr)
if argoutil.IsObjectFound(r.Client, cr.Namespace, common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName, cm) {
addSCMGitlabVolumeMount = true
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: "appset-gitlab-scm-tls-cert",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName,
},
},
},
})
}
}

podSpec.Containers = []corev1.Container{
applicationSetContainer(cr),
applicationSetContainer(cr, addSCMGitlabVolumeMount),
}
AddSeccompProfileForOpenShift(r.Client, podSpec)

Expand Down Expand Up @@ -185,7 +207,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD,

}

func applicationSetContainer(cr *argoproj.ArgoCD) corev1.Container {
func applicationSetContainer(cr *argoproj.ArgoCD, addSCMGitlabVolumeMount bool) corev1.Container {
// Global proxy env vars go first
appSetEnv := []corev1.EnvVar{{
Name: "NAMESPACE",
Expand All @@ -202,7 +224,7 @@ func applicationSetContainer(cr *argoproj.ArgoCD) corev1.Container {
// Environment specified in the CR take precedence over everything else
appSetEnv = argoutil.EnvMerge(appSetEnv, proxyEnvVars(), false)

return corev1.Container{
container := corev1.Container{
Command: getArgoApplicationSetCommand(cr),
Env: appSetEnv,
Image: getApplicationSetContainerImage(cr),
Expand Down Expand Up @@ -252,6 +274,13 @@ func applicationSetContainer(cr *argoproj.ArgoCD) corev1.Container {
RunAsNonRoot: boolPtr(true),
},
}
if addSCMGitlabVolumeMount {
container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
Name: "appset-gitlab-scm-tls-cert",
MountPath: cr.Spec.ApplicationSet.ScmRootCaPath,
})
}
return container
}

func (r *ReconcileArgoCD) reconcileApplicationSetServiceAccount(cr *argoproj.ArgoCD) (*corev1.ServiceAccount, error) {
Expand Down
36 changes: 30 additions & 6 deletions controllers/argocd/applicationset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"

argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
Expand Down Expand Up @@ -92,14 +93,14 @@ func TestReconcileApplicationSet_CreateDeployments(t *testing.T) {
deployment))

// Ensure the created Deployment has the expected properties
checkExpectedDeploymentValues(t, deployment, &sa, a)
checkExpectedDeploymentValues(t, r, deployment, &sa, a)
}

func checkExpectedDeploymentValues(t *testing.T, deployment *appsv1.Deployment, sa *corev1.ServiceAccount, a *argoproj.ArgoCD) {
func checkExpectedDeploymentValues(t *testing.T, r *ReconcileArgoCD, deployment *appsv1.Deployment, sa *corev1.ServiceAccount, a *argoproj.ArgoCD) {
assert.Equal(t, deployment.Spec.Template.Spec.ServiceAccountName, sa.ObjectMeta.Name)
appsetAssertExpectedLabels(t, &deployment.ObjectMeta)

want := []corev1.Container{applicationSetContainer(a)}
want := []corev1.Container{applicationSetContainer(a, false)}

if diff := cmp.Diff(want, deployment.Spec.Template.Spec.Containers); diff != "" {
t.Fatalf("failed to reconcile applicationset-controller deployment containers:\n%s", diff)
Expand Down Expand Up @@ -150,6 +151,19 @@ func checkExpectedDeploymentValues(t *testing.T, deployment *appsv1.Deployment,
},
}

if a.Spec.ApplicationSet.ScmRootCaPath != "" && argoutil.IsObjectFound(r.Client, a.Namespace, common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName, a) {
volumes = append(volumes, corev1.Volume{
Name: "appset-gitlab-scm-tls-cert",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName,
},
},
},
})
}

if diff := cmp.Diff(volumes, deployment.Spec.Template.Spec.Volumes); diff != "" {
t.Fatalf("failed to reconcile applicationset-controller deployment volumes:\n%s", diff)
}
Expand Down Expand Up @@ -261,7 +275,7 @@ func TestReconcileApplicationSet_UpdateExistingDeployments(t *testing.T) {
deployment))

// Ensure the updated Deployment has the expected properties
checkExpectedDeploymentValues(t, deployment, &sa, a)
checkExpectedDeploymentValues(t, r, deployment, &sa, a)

}

Expand All @@ -287,7 +301,7 @@ func TestReconcileApplicationSet_Deployments_resourceRequirements(t *testing.T)
assert.Equal(t, deployment.Spec.Template.Spec.ServiceAccountName, sa.ObjectMeta.Name)
appsetAssertExpectedLabels(t, &deployment.ObjectMeta)

containerWant := []corev1.Container{applicationSetContainer(a)}
containerWant := []corev1.Container{applicationSetContainer(a, false)}

if diff := cmp.Diff(containerWant, deployment.Spec.Template.Spec.Containers); diff != "" {
t.Fatalf("failed to reconcile argocd-server deployment:\n%s", diff)
Expand Down Expand Up @@ -346,6 +360,14 @@ func TestReconcileApplicationSet_Deployments_SpecOverride(t *testing.T) {
envVars: map[string]string{common.ArgoCDImageEnvName: "custom-env-image"},
expectedContainerImage: "custom-image:custom-version",
},
{
name: "ensure scm tls cert mount is present",
appSetField: &argoproj.ArgoCDApplicationSet{
ScmRootCaPath: "testPath",
},
envVars: map[string]string{common.ArgoCDImageEnvName: "custom-env-image"},
expectedContainerImage: "custom-env-image",
},
}

for _, test := range tests {
Expand All @@ -357,6 +379,8 @@ func TestReconcileApplicationSet_Deployments_SpecOverride(t *testing.T) {

a := makeTestArgoCD()
r := makeTestReconciler(t, a)
cm := newConfigMapWithName(getCAConfigMapName(a), a)
r.Client.Create(context.Background(), cm, &client.CreateOptions{})

a.Spec.ApplicationSet = test.appSetField

Expand All @@ -374,7 +398,7 @@ func TestReconcileApplicationSet_Deployments_SpecOverride(t *testing.T) {

specImage := deployment.Spec.Template.Spec.Containers[0].Image
assert.Equal(t, test.expectedContainerImage, specImage)

checkExpectedDeploymentValues(t, r, deployment, &sa, a)
})
}

Expand Down
2 changes: 1 addition & 1 deletion controllers/argocd/argocd_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,6 @@ func (r *ReconcileArgoCD) Reconcile(ctx context.Context, request ctrl.Request) (
// SetupWithManager sets up the controller with the Manager.
func (r *ReconcileArgoCD) SetupWithManager(mgr ctrl.Manager) error {
bldr := ctrl.NewControllerManagedBy(mgr)
r.setResourceWatches(bldr, r.clusterResourceMapper, r.tlsSecretMapper, r.namespaceResourceMapper, r.clusterSecretResourceMapper)
r.setResourceWatches(bldr, r.clusterResourceMapper, r.tlsSecretMapper, r.namespaceResourceMapper, r.clusterSecretResourceMapper, r.applicationSetSCMTLSConfigMapMapper)
return bldr.Complete(r)
}
28 changes: 28 additions & 0 deletions controllers/argocd/custommapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,31 @@ func (r *ReconcileArgoCD) clusterSecretResourceMapper(o client.Object) []reconci

return result
}

// applicationSetSCMTLSConfigMapMapper maps a watch event on a configmap with name "argocd-appset-gitlab-scm-tls-certs-cm",
// back to the ArgoCD object that we want to reconcile.
func (r *ReconcileArgoCD) applicationSetSCMTLSConfigMapMapper(o client.Object) []reconcile.Request {
var result = []reconcile.Request{}

if o.GetName() == common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName {
argocds := &argoproj.ArgoCDList{}
if err := r.Client.List(context.TODO(), argocds, &client.ListOptions{Namespace: o.GetNamespace()}); err != nil {
return result
}

if len(argocds.Items) != 1 {
return result
}

argocd := argocds.Items[0]
namespacedName := client.ObjectKey{
Name: argocd.Name,
Namespace: argocd.Namespace,
}
result = []reconcile.Request{
{NamespacedName: namespacedName},
}
}

return result
}
8 changes: 7 additions & 1 deletion controllers/argocd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ func removeString(slice []string, s string) []string {
}

// setResourceWatches will register Watches for each of the supported Resources.
func (r *ReconcileArgoCD) setResourceWatches(bldr *builder.Builder, clusterResourceMapper, tlsSecretMapper, namespaceResourceMapper, clusterSecretResourceMapper handler.MapFunc) *builder.Builder {
func (r *ReconcileArgoCD) setResourceWatches(bldr *builder.Builder, clusterResourceMapper, tlsSecretMapper, namespaceResourceMapper, clusterSecretResourceMapper, applicationSetGitlabSCMTLSConfigMapMapper handler.MapFunc) *builder.Builder {

deploymentConfigPred := predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
Expand Down Expand Up @@ -1046,12 +1046,18 @@ func (r *ReconcileArgoCD) setResourceWatches(bldr *builder.Builder, clusterResou

clusterSecretResourceHandler := handler.EnqueueRequestsFromMapFunc(clusterSecretResourceMapper)

appSetGitlabSCMTLSConfigMapHandler := handler.EnqueueRequestsFromMapFunc(applicationSetGitlabSCMTLSConfigMapMapper)

tlsSecretHandler := handler.EnqueueRequestsFromMapFunc(tlsSecretMapper)

bldr.Watches(&source.Kind{Type: &v1.ClusterRoleBinding{}}, clusterResourceHandler)

bldr.Watches(&source.Kind{Type: &v1.ClusterRole{}}, clusterResourceHandler)

bldr.Watches(&source.Kind{Type: &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDAppSetGitlabSCMTLSCertsConfigMapName,
}}}, appSetGitlabSCMTLSConfigMapHandler)

// Watch for secrets of type TLS that might be created by external processes
bldr.Watches(&source.Kind{Type: &corev1.Secret{Type: corev1.SecretTypeTLS}}, tlsSecretHandler)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6653,6 +6653,8 @@ spec:
to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
type: object
scmRootCaPath:
type: string
version:
description: Version is the Argo CD ApplicationSet image tag.
(optional)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 120
---
apiVersion: argoproj.io/v1beta1
kind: ArgoCD
metadata:
name: argocd
namespace: test-1-32-appsets-scm-tls-mount
spec:
applicationSet:
scmRootCaPath: /app/tls/cert
status:
phase: Available
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-applicationset-controller
namespace: test-1-32-appsets-scm-tls-mount
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/name: argocd-applicationset-controller
app.kubernetes.io/part-of: argocd-applicationset
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-applicationset-controller
template:
spec:
containers:
- command:
- entrypoint.sh
- argocd-applicationset-controller
- --argocd-repo-server
- argocd-repo-server.test-1-32-appsets-scm-tls-mount.svc.cluster.local:8081
- --loglevel
- info
- --scm-root-ca-path
- /app/tls/cert
volumeMounts:
- mountPath: /app/config/ssh
name: ssh-known-hosts
- mountPath: /app/config/tls
name: tls-certs
- mountPath: /app/config/gpg/source
name: gpg-keys
- mountPath: /app/config/gpg/keys
name: gpg-keyring
- mountPath: /tmp
name: tmp
- mountPath: /app/tls/cert
name: appset-gitlab-scm-tls-cert
volumes:
- configMap:
defaultMode: 420
name: argocd-ssh-known-hosts-cm
name: ssh-known-hosts
- configMap:
defaultMode: 420
name: argocd-tls-certs-cm
name: tls-certs
- configMap:
defaultMode: 420
name: argocd-gpg-keys-cm
name: gpg-keys
- emptyDir: {}
name: gpg-keyring
- emptyDir: {}
name: tmp
- configMap:
defaultMode: 420
name: argocd-appset-gitlab-scm-tls-certs-cm
name: appset-gitlab-scm-tls-cert
Loading
Loading