diff --git a/.github/workflows/spectro-release.yaml b/.github/workflows/spectro-release.yaml index cec3826349..cfbea75d85 100644 --- a/.github/workflows/spectro-release.yaml +++ b/.github/workflows/spectro-release.yaml @@ -7,6 +7,12 @@ on: description: 'Cluster API Version to Build' required: true default: '0.0.0' + rel_type: + type: choice + description: Type of release + options: + - release + - rc jobs: builder: # edge-runner machine group is a bunch of machines in US Datacenter @@ -15,6 +21,8 @@ jobs: # Ensure that the credentials are provided as encrypted secrets env: SPECTRO_VERSION: ${{ github.event.inputs.release_version }} + LEGACY_REGISTRY: gcr.io/spectro-images-public/release/cluster-api-aws + FIPS_REGISTRY: gcr.io/spectro-images-public/release-fips/cluster-api-aws steps: - uses: mukunku/tag-exists-action@v1.2.0 @@ -26,6 +34,11 @@ jobs: run: | echo "Tag already exists for v${{ github.event.inputs.release_version }}-spectro..." exit 1 + - + if: ${{ github.event.inputs.rel_type == 'rc' }} + run: | + echo "LEGACY_REGISTRY=gcr.io/spectro-dev-public/release/cluster-api-aws" >> $GITHUB_ENV + echo "FIPS_REGISTRY=gcr.io/spectro-dev-public/release-fips/cluster-api-aws" >> $GITHUB_ENV - uses: actions/checkout@v3 - @@ -41,7 +54,7 @@ jobs: - name: Build Image env: - REGISTRY: gcr.io/spectro-images-public/release/cluster-api-aws + REGISTRY: ${{ env.LEGACY_REGISTRY }} run: | make docker-build-all make docker-push-all @@ -49,12 +62,13 @@ jobs: name: Build Image - FIPS Mode env: FIPS_ENABLE: yes - REGISTRY: gcr.io/spectro-images-public/release-fips/cluster-api-aws + REGISTRY: ${{ env.FIPS_REGISTRY }} run: | make docker-build-all make docker-push-all - name: Create Release + if: ${{ github.event.inputs.rel_type == 'release' }} id: create_release uses: actions/create-release@v1 env: diff --git a/Dockerfile b/Dockerfile index 42692aa1ed..ddaba48ac6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,3 @@ -# syntax=docker/dockerfile:1.1-experimental - # Copyright 2019 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Makefile b/Makefile index 84190493d3..ea47b9b9a5 100644 --- a/Makefile +++ b/Makefile @@ -94,13 +94,14 @@ TOOLCHAIN_IMAGE := toolchain # Fips Flags FIPS_ENABLE ?= "" +BUILD_ARGS = --build-arg CRYPTO_LIB=${FIPS_ENABLE} --build-arg BUILDER_GOLANG_VERSION=${BUILDER_GOLANG_VERSION} RELEASE_LOC := release ifeq ($(FIPS_ENABLE),yes) RELEASE_LOC := release-fips endif -SPECTRO_VERSION ?= 4.0.0-dev +SPECTRO_VERSION ?= 4.1.0-dev TAG ?= v1.5.2-spectro-${SPECTRO_VERSION} ARCH ?= amd64 # ALL_ARCH = amd64 arm arm64 ppc64le s390x @@ -355,7 +356,7 @@ clusterawsadm: ## Build clusterawsadm binary .PHONY: docker-build docker-build: docker-pull-prerequisites ## Build the docker image for controller-manager - docker buildx build --platform linux/${ARCH} --build-arg CRYPTO_LIB=${FIPS_ENABLE} --build-arg ARCH=$(ARCH) --build-arg LDFLAGS="$(LDFLAGS)" . -t $(CORE_CONTROLLER_IMG)-$(ARCH):$(TAG) + docker buildx build --load --platform linux/${ARCH} ${BUILD_ARGS} --build-arg ARCH=$(ARCH) --build-arg LDFLAGS="$(LDFLAGS)" . -t $(CORE_CONTROLLER_IMG)-$(ARCH):$(TAG) @echo $(CORE_CONTROLLER_IMG)-$(ARCH):$(TAG) .PHONY: docker-build-all ## Build all the architecture docker images diff --git a/pkg/cloud/services/iam/iam.go b/pkg/cloud/services/iam/iam.go index 7f1e1c92db..c2bccbf751 100644 --- a/pkg/cloud/services/iam/iam.go +++ b/pkg/cloud/services/iam/iam.go @@ -40,7 +40,7 @@ const ( SelfsignedIssuerFormat = "%s-selfsigned-issuer" // S3HostFormat format for the host format for s3 for the oidc provider. - S3HostFormat = "s3-%s.amazonaws.com" + S3HostFormat = "s3.%s.amazonaws.com" // STSAWSAudience security token service url. STSAWSAudience = "sts.amazonaws.com" diff --git a/pkg/cloud/services/iam/podidentitywebhook.go b/pkg/cloud/services/iam/podidentitywebhook.go index 7ba6f86247..8901d6cd07 100644 --- a/pkg/cloud/services/iam/podidentitywebhook.go +++ b/pkg/cloud/services/iam/podidentitywebhook.go @@ -12,14 +12,16 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( podIdentityWebhookName = "pod-identity-webhook" - podIdentityWebhookImage = "amazon/amazon-eks-pod-identity-webhook:v0.4.0" + podIdentityWebhookImage = "amazon/amazon-eks-pod-identity-webhook:v0.5.2" + + labelNodeRoleMaster = "node-role.kubernetes.io/master" + labelNodeRoleControlPlane = "node-role.kubernetes.io/control-plane" ) func reconcileServiceAccount(ctx context.Context, ns string, remoteClient client.Client) error { @@ -155,67 +157,160 @@ func reconcileDeployment(ctx context.Context, ns string, secret *corev1.Secret, return err } - if check.UID != "" { - return nil - } - - replicas := int32(1) - deployment := &v13.Deployment{ - ObjectMeta: objectMeta(podIdentityWebhookName, ns), - Spec: v13.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": podIdentityWebhookName, + nodeAffinity := &corev1.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.PreferredSchedulingTerm{ + { + Weight: 10, + Preference: corev1.NodeSelectorTerm{ + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: labelNodeRoleMaster, + Operator: corev1.NodeSelectorOpExists, + }, { + Key: labelNodeRoleControlPlane, + Operator: corev1.NodeSelectorOpExists, + }, + }, + }, + }, { + Weight: 10, + Preference: corev1.NodeSelectorTerm{ + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: labelNodeRoleControlPlane, + Operator: corev1.NodeSelectorOpExists, + }, + }, }, }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ + }, + } + + tolerations := []corev1.Toleration{ + { + Key: labelNodeRoleControlPlane, + Effect: corev1.TaintEffectNoSchedule, + }, { + Key: labelNodeRoleMaster, + Effect: corev1.TaintEffectNoSchedule, + }, + } + + if check.UID == "" { + replicas := int32(1) + + deployment := &v13.Deployment{ + ObjectMeta: objectMeta(podIdentityWebhookName, ns), + Spec: v13.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ "app": podIdentityWebhookName, }, }, - Spec: corev1.PodSpec{ - ServiceAccountName: podIdentityWebhookName, - Containers: []corev1.Container{ - { - Name: podIdentityWebhookName, - Image: podIdentityWebhookImage, - ImagePullPolicy: corev1.PullIfNotPresent, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "webhook-certs", - MountPath: "/etc/webhook/certs/", - ReadOnly: false, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": podIdentityWebhookName, + }, + }, + Spec: corev1.PodSpec{ + Affinity: &corev1.Affinity{NodeAffinity: nodeAffinity}, + Tolerations: tolerations, + ServiceAccountName: podIdentityWebhookName, + Containers: []corev1.Container{ + { + Name: podIdentityWebhookName, + Image: podIdentityWebhookImage, + ImagePullPolicy: corev1.PullIfNotPresent, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "webhook-certs", + MountPath: "/etc/webhook/certs/", + ReadOnly: false, + }, + }, + Command: []string{ + "/webhook", + "--in-cluster=false", + "--namespace=" + ns, + "--service-name=" + podIdentityWebhookName, + "--annotation-prefix=eks.amazonaws.com", + "--token-audience=sts.amazonaws.com", + "--logtostderr", }, - }, - Command: []string{ - "/webhook", - "--in-cluster=false", - "--namespace=" + ns, - "--service-name=" + podIdentityWebhookName, - "--annotation-prefix=eks.amazonaws.com", - "--token-audience=sts.amazonaws.com", - "--logtostderr", }, }, - }, - Volumes: []corev1.Volume{ - { - Name: "webhook-certs", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: secret.Name, + Volumes: []corev1.Volume{ + { + Name: "webhook-certs", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secret.Name, + }, }, }, }, }, }, }, - }, + } + + return remoteClient.Create(ctx, deployment) + } + + needsUpdate := false + for ci, container := range check.Spec.Template.Spec.Containers { + if container.Name == podIdentityWebhookName && container.Image != podIdentityWebhookImage { + check.Spec.Template.Spec.Containers[ci].Image = podIdentityWebhookImage + needsUpdate = true + } + } + + if check.Spec.Template.Spec.Affinity == nil { + check.Spec.Template.Spec.Affinity = &corev1.Affinity{} + } + if check.Spec.Template.Spec.Affinity.NodeAffinity == nil { + check.Spec.Template.Spec.Affinity.NodeAffinity = &corev1.NodeAffinity{} + } + + for _, aff := range nodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution { + found := false + for _, a := range check.Spec.Template.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution { + if len(a.Preference.MatchExpressions) == len(aff.Preference.MatchExpressions) { + for _, e := range a.Preference.MatchExpressions { + for _, e2 := range aff.Preference.MatchExpressions { + if e.Key == e2.Key && e.Operator == e2.Operator { + found = true + } + } + } + } + } + if !found { + check.Spec.Template.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution = append(check.Spec.Template.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution, aff) + needsUpdate = true + } } - return remoteClient.Create(ctx, deployment) + for _, tol := range tolerations { + found := false + for _, t := range check.Spec.Template.Spec.Tolerations { + if t.Key == tol.Key && t.Effect == tol.Effect { + found = true + } + } + if !found { + check.Spec.Template.Spec.Tolerations = append(check.Spec.Template.Spec.Tolerations, tol) + needsUpdate = true + } + } + + if needsUpdate { + return remoteClient.Update(ctx, check) + } + + return nil } func reconcileMutatingWebHook(ctx context.Context, ns string, secret *corev1.Secret, remoteClient client.Client) error { @@ -319,8 +414,8 @@ func objectMeta(name, namespace string) metav1.ObjectMeta { return meta } -// reconcileCertifcateSecret takes a secret and moves it to the workload cluster. -func reconcileCertifcateSecret(ctx context.Context, cert *corev1.Secret, remoteClient client.Client) error { +// reconcileCertificateSecret takes a secret and moves it to the workload cluster. +func reconcileCertificateSecret(ctx context.Context, cert *corev1.Secret, remoteClient client.Client) error { // check if the secret was created by cert-manager certCheck := &corev1.Secret{} if err := remoteClient.Get(ctx, types.NamespacedName{ diff --git a/pkg/cloud/services/iam/reconcilers.go b/pkg/cloud/services/iam/reconcilers.go index 39c9ecda7b..e09ff81e78 100644 --- a/pkg/cloud/services/iam/reconcilers.go +++ b/pkg/cloud/services/iam/reconcilers.go @@ -13,7 +13,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/converters" clusterapiv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -43,7 +42,7 @@ func (s *Service) reconcilePodIdentityWebhook(ctx context.Context) error { } // switch it to kube-system and move it to the remote cluster - if err := reconcileCertifcateSecret(ctx, certSecret, remoteClient); err != nil { + if err := reconcileCertificateSecret(ctx, certSecret, remoteClient); err != nil { return err }