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

Backport of [NET-10985] Fix bug where imagePullSecrets were not set up for Gateways into release/1.4.x #4373

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
5 changes: 5 additions & 0 deletions .changelog/4316.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```release-note:bug
api-gateway: `global.imagePullSecrets` are now configured on the `ServiceAccount` for `Gateways`.

Note: the referenced image pull Secret(s) must be present in the same namespace the `Gateway` is deployed to.
```
18 changes: 18 additions & 0 deletions charts/consul/templates/connect-inject-configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{- if .Values.connectInject.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "consul.fullname" . }}-connect-inject-config
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
component: connect-injector
data:
config.json: |
{
"image_pull_secrets": {{ .Values.global.imagePullSecrets | toJson }}
}
{{- end }}
7 changes: 7 additions & 0 deletions charts/consul/templates/connect-inject-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ spec:
- "-ec"
- |
exec consul-k8s-control-plane inject-connect \
-config-file=/consul/config/config.json \
{{- if .Values.global.federation.enabled }}
-enable-federation \
{{- end }}
Expand Down Expand Up @@ -317,6 +318,9 @@ spec:
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- name: config
mountPath: /consul/config
readOnly: true
{{- if not (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName) }}
- name: certs
mountPath: /etc/connect-injector/certs
Expand All @@ -332,6 +336,9 @@ spec:
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ template "consul.fullname" . }}-connect-inject-config
{{- if not (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName) }}
- name: certs
secret:
Expand Down
4 changes: 3 additions & 1 deletion control-plane/api-gateway/common/helm_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ type HelmConfig struct {
// ImageDataplane is the Consul Dataplane image to use in gateway deployments.
ImageDataplane string
// ImageConsulK8S is the Consul Kubernetes Control Plane image to use in gateway deployments.
ImageConsulK8S string
ImageConsulK8S string
// ImagePullSecrets reference one or more Secret(s) that contain the credentials to pull images from private image repos.
ImagePullSecrets []v1.LocalObjectReference
ConsulDestinationNamespace string
NamespaceMirroringPrefix string
EnableNamespaces bool
Expand Down
4 changes: 3 additions & 1 deletion control-plane/api-gateway/gatekeeper/gatekeeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ func (g *Gatekeeper) namespacedName(gateway gwv1beta1.Gateway) types.NamespacedN
}

func (g *Gatekeeper) serviceAccountName(gateway gwv1beta1.Gateway, config common.HelmConfig) string {
if config.AuthMethod == "" && !config.EnableOpenShift {
// We only create a ServiceAccount if it's needed for RBAC or image pull secrets;
// otherwise, we clean up if one was previously created.
if config.AuthMethod == "" && !config.EnableOpenShift && len(config.ImagePullSecrets) == 0 {
return ""
}
return gateway.Name
Expand Down
51 changes: 29 additions & 22 deletions control-plane/api-gateway/gatekeeper/gatekeeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,13 @@ func TestUpsert(t *testing.T) {
},
},
helmConfig: common.HelmConfig{
ImageDataplane: dataplaneImage,
ImageDataplane: dataplaneImage,
ImagePullSecrets: []corev1.LocalObjectReference{{Name: "my-secret"}},
},
initialResources: resources{},
finalResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "1"),
},
roles: []*rbac.Role{},
services: []*corev1.Service{
Expand All @@ -219,7 +220,9 @@ func TestUpsert(t *testing.T) {
},
}, "1", false, false),
},
serviceAccounts: []*corev1.ServiceAccount{},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1", []corev1.LocalObjectReference{{Name: "my-secret"}}),
},
},
},
"create a new gateway deployment with managed Service": {
Expand Down Expand Up @@ -271,7 +274,6 @@ func TestUpsert(t *testing.T) {
},
}, "1", false, false),
},
serviceAccounts: []*corev1.ServiceAccount{},
},
},
"create a new gateway deployment with managed Service and ACLs": {
Expand Down Expand Up @@ -299,13 +301,14 @@ func TestUpsert(t *testing.T) {
},
},
helmConfig: common.HelmConfig{
AuthMethod: "method",
ImageDataplane: dataplaneImage,
AuthMethod: "method",
ImageDataplane: dataplaneImage,
ImagePullSecrets: []corev1.LocalObjectReference{{Name: "my-secret"}},
},
initialResources: resources{},
finalResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "1"),
},
roles: []*rbac.Role{
configureRole(name, namespace, labels, "1", false),
Expand All @@ -330,7 +333,7 @@ func TestUpsert(t *testing.T) {
}, "1", false, false),
},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", []corev1.LocalObjectReference{{Name: "my-secret"}}),
},
},
},
Expand Down Expand Up @@ -438,7 +441,7 @@ func TestUpsert(t *testing.T) {
},
initialResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "1"),
},
roles: []*rbac.Role{
configureRole(name, namespace, labels, "1", false),
Expand All @@ -456,12 +459,12 @@ func TestUpsert(t *testing.T) {
}, "1", true, false),
},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", nil),
},
},
finalResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "2"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "2"),
},
roles: []*rbac.Role{
configureRole(name, namespace, labels, "1", false),
Expand All @@ -486,7 +489,7 @@ func TestUpsert(t *testing.T) {
}, "2", false, false),
},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", nil),
},
},
ignoreTimestampOnService: true,
Expand Down Expand Up @@ -523,7 +526,7 @@ func TestUpsert(t *testing.T) {
},
initialResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "1"),
},
roles: []*rbac.Role{
configureRole(name, namespace, labels, "1", false),
Expand All @@ -546,12 +549,12 @@ func TestUpsert(t *testing.T) {
}, "1", true, false),
},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", nil),
},
},
finalResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "2"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "2"),
},
roles: []*rbac.Role{
configureRole(name, namespace, labels, "1", false),
Expand All @@ -570,7 +573,7 @@ func TestUpsert(t *testing.T) {
}, "2", false, false),
},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", nil),
},
},
ignoreTimestampOnService: true,
Expand Down Expand Up @@ -924,7 +927,7 @@ func TestUpsert(t *testing.T) {
},
finalResources: resources{
deployments: []*appsv1.Deployment{
configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"),
configureDeployment(name, namespace, labels, 3, nil, nil, name, "1"),
},
roles: []*rbac.Role{
configureRole(name, namespace, labels, "1", true),
Expand All @@ -934,7 +937,7 @@ func TestUpsert(t *testing.T) {
},
services: []*corev1.Service{},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", nil),
},
},
},
Expand Down Expand Up @@ -1114,7 +1117,7 @@ func TestDelete(t *testing.T) {
}, "1", true, false),
},
serviceAccounts: []*corev1.ServiceAccount{
configureServiceAccount(name, namespace, labels, "1"),
configureServiceAccount(name, namespace, labels, "1", nil),
},
},
finalResources: resources{
Expand Down Expand Up @@ -1210,6 +1213,9 @@ func validateResourcesExist(t *testing.T, client client.Client, helmConfig commo
require.Equal(t, expected.Spec.Template.ObjectMeta.Annotations, actual.Spec.Template.ObjectMeta.Annotations)
require.Equal(t, expected.Spec.Template.ObjectMeta.Labels, actual.Spec.Template.Labels)

// Ensure the service account is assigned
require.Equal(t, expected.Spec.Template.Spec.ServiceAccountName, actual.Spec.Template.Spec.ServiceAccountName)

// Ensure there is an init container
hasInitContainer := false
for _, container := range actual.Spec.Template.Spec.InitContainers {
Expand Down Expand Up @@ -1403,7 +1409,7 @@ func validateResourcesAreDeleted(t *testing.T, k8sClient client.Client, resource
return nil
}

func configureDeployment(name, namespace string, labels map[string]string, replicas int32, nodeSelector map[string]string, tolerations []corev1.Toleration, serviceAccoutName, resourceVersion string) *appsv1.Deployment {
func configureDeployment(name, namespace string, labels map[string]string, replicas int32, nodeSelector map[string]string, tolerations []corev1.Toleration, serviceAccountName, resourceVersion string) *appsv1.Deployment {
return &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
APIVersion: "apps/v1",
Expand Down Expand Up @@ -1456,7 +1462,7 @@ func configureDeployment(name, namespace string, labels map[string]string, repli
},
NodeSelector: nodeSelector,
Tolerations: tolerations,
ServiceAccountName: serviceAccoutName,
ServiceAccountName: serviceAccountName,
},
},
},
Expand Down Expand Up @@ -1580,7 +1586,7 @@ func configureService(name, namespace string, labels, annotations map[string]str
return &service
}

func configureServiceAccount(name, namespace string, labels map[string]string, resourceVersion string) *corev1.ServiceAccount {
func configureServiceAccount(name, namespace string, labels map[string]string, resourceVersion string, pullSecrets []corev1.LocalObjectReference) *corev1.ServiceAccount {
return &corev1.ServiceAccount{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Expand All @@ -1601,6 +1607,7 @@ func configureServiceAccount(name, namespace string, labels map[string]string, r
},
},
},
ImagePullSecrets: pullSecrets,
}
}

Expand Down
2 changes: 1 addition & 1 deletion control-plane/api-gateway/gatekeeper/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type initContainerCommandData struct {
LogJSON bool
}

// containerInit returns the init container spec for connect-init that polls for the service and the connect proxy service to be registered
// initContainer returns the init container spec for connect-init that polls for the service and the connect proxy service to be registered
// so that it can save the proxy service id to the shared volume and boostrap Envoy with the proxy-id.
func (g Gatekeeper) initContainer(config common.HelmConfig, name, namespace string) (corev1.Container, error) {
data := initContainerCommandData{
Expand Down
7 changes: 4 additions & 3 deletions control-plane/api-gateway/gatekeeper/rolebinding.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import (
"k8s.io/apimachinery/pkg/types"
gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"

"github.com/hashicorp/consul-k8s/control-plane/api-gateway/common"
"github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1"
rbac "k8s.io/api/rbac/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"

"github.com/hashicorp/consul-k8s/control-plane/api-gateway/common"
"github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1"
)

func (g *Gatekeeper) upsertRoleBinding(ctx context.Context, gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) error {
Expand Down Expand Up @@ -65,7 +66,7 @@ func (g *Gatekeeper) deleteRoleBinding(ctx context.Context, gwName types.Namespa

func (g *Gatekeeper) roleBinding(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) *rbac.RoleBinding {
// Create resources for reference. This avoids bugs if naming patterns change.
serviceAccount := g.serviceAccount(gateway)
serviceAccount := g.serviceAccount(gateway, config)
role := g.role(gateway, gcc, config)

return &rbac.RoleBinding{
Expand Down
22 changes: 11 additions & 11 deletions control-plane/api-gateway/gatekeeper/serviceaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ import (
"context"
"errors"

"github.com/hashicorp/consul-k8s/control-plane/api-gateway/common"
"k8s.io/apimachinery/pkg/types"
gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"

corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"

"github.com/hashicorp/consul-k8s/control-plane/api-gateway/common"
)

func (g *Gatekeeper) upsertServiceAccount(ctx context.Context, gateway gwv1beta1.Gateway, config common.HelmConfig) error {
if config.AuthMethod == "" && !config.EnableOpenShift {
// We only create a ServiceAccount if it's needed for RBAC or image pull secrets;
// otherwise, we clean up if one was previously created.
if config.AuthMethod == "" && !config.EnableOpenShift && len(config.ImagePullSecrets) == 0 {
return g.deleteServiceAccount(ctx, types.NamespacedName{Namespace: gateway.Namespace, Name: gateway.Name})
}

Expand Down Expand Up @@ -47,15 +49,12 @@ func (g *Gatekeeper) upsertServiceAccount(ctx context.Context, gateway gwv1beta1
}

// Create the ServiceAccount.
serviceAccount = g.serviceAccount(gateway)
serviceAccount = g.serviceAccount(gateway, config)
if err := ctrl.SetControllerReference(&gateway, serviceAccount, g.Client.Scheme()); err != nil {
return err
}
if err := g.Client.Create(ctx, serviceAccount); err != nil {
return err
}

return nil
return g.Client.Create(ctx, serviceAccount)
}

func (g *Gatekeeper) deleteServiceAccount(ctx context.Context, gwName types.NamespacedName) error {
Expand All @@ -69,12 +68,13 @@ func (g *Gatekeeper) deleteServiceAccount(ctx context.Context, gwName types.Name
return nil
}

func (g *Gatekeeper) serviceAccount(gateway gwv1beta1.Gateway) *corev1.ServiceAccount {
func (g *Gatekeeper) serviceAccount(gateway gwv1beta1.Gateway, config common.HelmConfig) *corev1.ServiceAccount {
return &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: gateway.Name,
Namespace: gateway.Namespace,
Labels: common.LabelsForGateway(&gateway),
},
ImagePullSecrets: config.ImagePullSecrets,
}
}
2 changes: 2 additions & 0 deletions control-plane/subcommand/inject-connect/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Command struct {
flagListen string
flagCertDir string // Directory with TLS certs for listening (PEM)
flagDefaultInject bool // True to inject by default
flagConfigFile string // Path to a config file in JSON format
flagConsulImage string // Docker image for Consul
flagConsulDataplaneImage string // Docker image for Envoy
flagConsulK8sImage string // Docker image for consul-k8s
Expand Down Expand Up @@ -183,6 +184,7 @@ func init() {
func (c *Command) init() {
c.flagSet = flag.NewFlagSet("", flag.ContinueOnError)
c.flagSet.StringVar(&c.flagListen, "listen", ":8080", "Address to bind listener to.")
c.flagSet.StringVar(&c.flagConfigFile, "config-file", "", "Path to a JSON config file.")
c.flagSet.Var((*flags.FlagMapValue)(&c.flagNodeMeta), "node-meta",
"Metadata to set on the node, formatted as key=value. This flag may be specified multiple times to set multiple meta fields.")
c.flagSet.BoolVar(&c.flagDefaultInject, "default-inject", true, "Inject by default.")
Expand Down
Loading
Loading