Skip to content

Commit

Permalink
Allow tiller-proxy and AppRepository controller to use a custom CA (#878
Browse files Browse the repository at this point in the history
)

* Allow tiller-proxy and AppRepository controller to use a custom CA for a registry

* Fix unit tests and add more

* Move CA definition to AppRepository CRD

* Temporary use unreleased image for chartrepo
  • Loading branch information
andresmgot committed Dec 20, 2018
1 parent a6f3dc5 commit cf8c93f
Show file tree
Hide file tree
Showing 11 changed files with 378 additions and 42 deletions.
3 changes: 2 additions & 1 deletion chart/kubeapps/values.yaml
Expand Up @@ -100,7 +100,8 @@ apprepository:
syncImage:
registry: quay.io
repository: helmpack/chart-repo
tag: v1.0.2
# TODO: Update tag when a new release is available
tag: "@sha256:bf4b31604ec35e8317079546f6e06b2f045958feff5903e2705b76bf3fcbee4b"
initialRepos:
- name: stable
url: https://kubernetes-charts.storage.googleapis.com
Expand Down
32 changes: 27 additions & 5 deletions cmd/apprepository-controller/controller.go
Expand Up @@ -423,6 +423,26 @@ func newSyncJob(apprepo *apprepov1alpha1.AppRepository) *batchv1.Job {

// jobSpec returns a batchv1.JobSpec for running the chart-repo sync job
func syncJobSpec(apprepo *apprepov1alpha1.AppRepository) batchv1.JobSpec {
volumes := []corev1.Volume{}
volumeMounts := []corev1.VolumeMount{}
if apprepo.Spec.Auth.CustomCA != nil {
volumes = append(volumes, corev1.Volume{
Name: apprepo.Spec.Auth.CustomCA.SecretKeyRef.Name,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: apprepo.Spec.Auth.CustomCA.SecretKeyRef.Name,
Items: []corev1.KeyToPath{
{Key: apprepo.Spec.Auth.CustomCA.SecretKeyRef.Key, Path: "ca.crt"},
},
},
},
})
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: apprepo.Spec.Auth.CustomCA.SecretKeyRef.Name,
ReadOnly: true,
MountPath: "/usr/local/share/ca-certificates",
})
}
return batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -435,13 +455,15 @@ func syncJobSpec(apprepo *apprepov1alpha1.AppRepository) batchv1.JobSpec {
RestartPolicy: "OnFailure",
Containers: []corev1.Container{
{
Name: "sync",
Image: repoSyncImage,
Command: []string{"/chart-repo"},
Args: apprepoSyncJobArgs(apprepo),
Env: apprepoSyncJobEnvVars(apprepo),
Name: "sync",
Image: repoSyncImage,
Command: []string{"/chart-repo"},
Args: apprepoSyncJobArgs(apprepo),
Env: apprepoSyncJobEnvVars(apprepo),
VolumeMounts: volumeMounts,
},
},
Volumes: volumes,
},
},
}
Expand Down
196 changes: 196 additions & 0 deletions cmd/apprepository-controller/controller_test.go
Expand Up @@ -85,8 +85,10 @@ func Test_newCronJob(t *testing.T) {
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "mongodb"}, Key: "mongodb-root-password"}},
},
},
VolumeMounts: []corev1.VolumeMount{},
},
},
Volumes: []corev1.Volume{},
},
},
},
Expand Down Expand Up @@ -169,8 +171,10 @@ func Test_newCronJob(t *testing.T) {
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "apprepo-my-charts-secrets"}, Key: "AuthorizationHeader"}},
},
},
VolumeMounts: []corev1.VolumeMount{},
},
},
Volumes: []corev1.Volume{},
},
},
},
Expand Down Expand Up @@ -265,8 +269,10 @@ func Test_newSyncJob(t *testing.T) {
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "mongodb"}, Key: "mongodb-root-password"}},
},
},
VolumeMounts: []corev1.VolumeMount{},
},
},
Volumes: []corev1.Volume{},
},
},
},
Expand Down Expand Up @@ -344,14 +350,204 @@ func Test_newSyncJob(t *testing.T) {
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "apprepo-my-charts-secrets"}, Key: "AuthorizationHeader"}},
},
},
VolumeMounts: []corev1.VolumeMount{},
},
},
Volumes: []corev1.Volume{},
},
},
},
},
"kubeapps/v2.3",
},
{
"my-charts with a customCA",
&apprepov1alpha1.AppRepository{
TypeMeta: metav1.TypeMeta{
Kind: "AppRepository",
APIVersion: "kubeapps.com/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "my-charts",
Namespace: "kubeapps",
Labels: map[string]string{
"name": "my-charts",
"created-by": "kubeapps",
},
},
Spec: apprepov1alpha1.AppRepositorySpec{
Type: "helm",
URL: "https://charts.acme.com/my-charts",
Auth: apprepov1alpha1.AppRepositoryAuth{
CustomCA: &apprepov1alpha1.AppRepositoryCustomCA{
SecretKeyRef: corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "ca-cert-test"}, Key: "foo"},
},
},
},
},
batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "apprepo-sync-my-charts-",
Namespace: "kubeapps",
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(
&apprepov1alpha1.AppRepository{ObjectMeta: metav1.ObjectMeta{Name: "my-charts"}},
schema.GroupVersionKind{
Group: apprepov1alpha1.SchemeGroupVersion.Group,
Version: apprepov1alpha1.SchemeGroupVersion.Version,
Kind: "AppRepository",
},
),
},
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"apprepositories.kubeapps.com/repo-name": "my-charts"},
},
Spec: corev1.PodSpec{
RestartPolicy: "OnFailure",
Containers: []corev1.Container{
{
Name: "sync",
Image: repoSyncImage,
Command: []string{"/chart-repo"},
Args: []string{
"sync",
"--mongo-url=mongodb.kubeapps",
"--mongo-user=root",
"my-charts",
"https://charts.acme.com/my-charts",
},
Env: []corev1.EnvVar{
{
Name: "MONGO_PASSWORD",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "mongodb"}, Key: "mongodb-root-password"}},
},
},
VolumeMounts: []corev1.VolumeMount{{
Name: "ca-cert-test",
ReadOnly: true,
MountPath: "/usr/local/share/ca-certificates",
}},
},
},
Volumes: []corev1.Volume{{
Name: "ca-cert-test",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "ca-cert-test",
Items: []corev1.KeyToPath{
{Key: "foo", Path: "ca.crt"},
},
},
},
}},
},
},
},
},
"",
},
{
"my-charts with a customCA and auth header",
&apprepov1alpha1.AppRepository{
TypeMeta: metav1.TypeMeta{
Kind: "AppRepository",
APIVersion: "kubeapps.com/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "my-charts",
Namespace: "kubeapps",
Labels: map[string]string{
"name": "my-charts",
"created-by": "kubeapps",
},
},
Spec: apprepov1alpha1.AppRepositorySpec{
Type: "helm",
URL: "https://charts.acme.com/my-charts",
Auth: apprepov1alpha1.AppRepositoryAuth{
CustomCA: &apprepov1alpha1.AppRepositoryCustomCA{
SecretKeyRef: corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "ca-cert-test"}, Key: "foo"},
},
Header: &apprepov1alpha1.AppRepositoryAuthHeader{
SecretKeyRef: corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "apprepo-my-charts-secrets"}, Key: "AuthorizationHeader"},
},
},
},
},
batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "apprepo-sync-my-charts-",
Namespace: "kubeapps",
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(
&apprepov1alpha1.AppRepository{ObjectMeta: metav1.ObjectMeta{Name: "my-charts"}},
schema.GroupVersionKind{
Group: apprepov1alpha1.SchemeGroupVersion.Group,
Version: apprepov1alpha1.SchemeGroupVersion.Version,
Kind: "AppRepository",
},
),
},
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"apprepositories.kubeapps.com/repo-name": "my-charts"},
},
Spec: corev1.PodSpec{
RestartPolicy: "OnFailure",
Containers: []corev1.Container{
{
Name: "sync",
Image: repoSyncImage,
Command: []string{"/chart-repo"},
Args: []string{
"sync",
"--mongo-url=mongodb.kubeapps",
"--mongo-user=root",
"my-charts",
"https://charts.acme.com/my-charts",
},
Env: []corev1.EnvVar{
{
Name: "MONGO_PASSWORD",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "mongodb"}, Key: "mongodb-root-password"}},
},
{
Name: "AUTHORIZATION_HEADER",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "apprepo-my-charts-secrets"}, Key: "AuthorizationHeader"}},
},
},
VolumeMounts: []corev1.VolumeMount{{
Name: "ca-cert-test",
ReadOnly: true,
MountPath: "/usr/local/share/ca-certificates",
}},
},
},
Volumes: []corev1.Volume{{
Name: "ca-cert-test",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "ca-cert-test",
Items: []corev1.KeyToPath{
{Key: "foo", Path: "ca.crt"},
},
},
},
}},
},
},
},
},
"",
},
}

for _, tt := range tests {
Expand Down
Expand Up @@ -44,14 +44,20 @@ type AppRepositorySpec struct {

// AppRepositoryAuth is the auth for an AppRepository resource
type AppRepositoryAuth struct {
Header *AppRepositoryAuthHeader `json:"header,omitempty"`
Header *AppRepositoryAuthHeader `json:"header,omitempty"`
CustomCA *AppRepositoryCustomCA `json:"customCA,omitempty"`
}

type AppRepositoryAuthHeader struct {
// Selects a key of a secret in the pod's namespace
SecretKeyRef corev1.SecretKeySelector `json:"secretKeyRef,omitempty"`
}

type AppRepositoryCustomCA struct {
// Selects a key of a secret in the pod's namespace
SecretKeyRef corev1.SecretKeySelector `json:"secretKeyRef,omitempty"`
}

// AppRepositoryStatus is the status for an AppRepository resource
type AppRepositoryStatus struct {
Status string `json:"status"`
Expand Down

0 comments on commit cf8c93f

Please sign in to comment.