Skip to content

Commit

Permalink
Accept service account issuer for Pod based IAM
Browse files Browse the repository at this point in the history
EKS-A users can leverage the IAM Role for Service Account (IRSA)
feature following the [special instructions for DIY Kubernetes]
(https://github.com/aws/amazon-eks-pod-identity-webhook/blob/master/SELF_HOSTED_SETUP.md)
to enable AWS authentication. This commit enables that by allowing
the configuration of service-account-issuer flag for kube-apiserver
with the identity issuer URL as per the self-hosted setup guide.
  • Loading branch information
mrajashree committed Nov 17, 2021
1 parent 21b35aa commit 05659db
Show file tree
Hide file tree
Showing 12 changed files with 1,325 additions and 0 deletions.
7 changes: 7 additions & 0 deletions config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ spec:
description: 'Deprecated: This field has no function and is going
to be removed in a future release.'
type: string
podIamConfig:
properties:
serviceAccountIssuer:
type: string
required:
- serviceAccountIssuer
type: object
proxyConfiguration:
properties:
httpProxy:
Expand Down
11 changes: 11 additions & 0 deletions pkg/api/v1alpha1/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ var clusterConfigValidations = []func(*Cluster) error{
validateIdentityProviderRefs,
validateProxyConfig,
validateMirrorConfig,
validatePodIAMConfig,
}

func GetClusterConfig(fileName string) (*Cluster, error) {
Expand Down Expand Up @@ -465,3 +466,13 @@ func validateGitOps(clusterConfig *Cluster) error {
}
return nil
}

func validatePodIAMConfig(clusterConfig *Cluster) error {
if clusterConfig.Spec.PodIAMConfig == nil {
return nil
}
if clusterConfig.Spec.PodIAMConfig.ServiceAccountIssuer == "" {
return errors.New("ServiceAccount Issuer can't be empty while configuring IAM roles for pods")
}
return nil
}
15 changes: 15 additions & 0 deletions pkg/api/v1alpha1/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type ClusterSpec struct {
ProxyConfiguration *ProxyConfiguration `json:"proxyConfiguration,omitempty"`
RegistryMirrorConfiguration *RegistryMirrorConfiguration `json:"registryMirrorConfiguration,omitempty"`
ManagementCluster ManagementCluster `json:"managementCluster,omitempty"`
PodIAMConfig *PodIAMConfig `json:"podIamConfig,omitempty"`
}

func (n *Cluster) Equal(o *Cluster) bool {
Expand Down Expand Up @@ -363,6 +364,20 @@ func (n *ManagementCluster) Equal(o ManagementCluster) bool {
return n.Name == o.Name
}

type PodIAMConfig struct {
ServiceAccountIssuer string `json:"serviceAccountIssuer"`
}

func (n *PodIAMConfig) Equal(o *PodIAMConfig) bool {
if n == o {
return true
}
if n == nil || o == nil {
return false
}
return n.ServiceAccountIssuer == o.ServiceAccountIssuer
}

// +kubebuilder:object:root=true
// Cluster is the Schema for the clusters API
type Cluster struct {
Expand Down
49 changes: 49 additions & 0 deletions pkg/api/v1alpha1/cluster_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,55 @@ func TestRegistryMirrorConfigurationEqual(t *testing.T) {
}
}

func TestPodIAMServiceAccountIssuerHasNotChanged(t *testing.T) {
testCases := []struct {
testName string
cluster1PodIAMConfig, cluster2PodIAMConfig *v1alpha1.PodIAMConfig
want bool
}{
{
testName: "both nil",
cluster1PodIAMConfig: nil,
cluster2PodIAMConfig: nil,
want: true,
},
{
testName: "one nil, one exists",
cluster1PodIAMConfig: &v1alpha1.PodIAMConfig{
ServiceAccountIssuer: "https://test",
},
cluster2PodIAMConfig: nil,
want: false,
},
{
testName: "both exist, same",
cluster1PodIAMConfig: &v1alpha1.PodIAMConfig{
ServiceAccountIssuer: "https://test",
},
cluster2PodIAMConfig: &v1alpha1.PodIAMConfig{
ServiceAccountIssuer: "https://test",
},
want: true,
},
{
testName: "both exist, service account issuer different",
cluster1PodIAMConfig: &v1alpha1.PodIAMConfig{
ServiceAccountIssuer: "https://test1",
},
cluster2PodIAMConfig: &v1alpha1.PodIAMConfig{
ServiceAccountIssuer: "https://test2",
},
want: false,
},
}
for _, tt := range testCases {
t.Run(tt.testName, func(t *testing.T) {
g := NewWithT(t)
g.Expect(tt.cluster1PodIAMConfig.Equal(tt.cluster2PodIAMConfig)).To(Equal(tt.want))
})
}
}

func setSelfManaged(c *v1alpha1.Cluster, s bool) {
if s {
c.SetSelfManaged()
Expand Down
3 changes: 3 additions & 0 deletions pkg/providers/docker/config/template-cp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ spec:
audit-log-maxbackup: "10"
audit-log-maxsize: "512"
profiling: "false"
{{- if .serviceAccountIssuer }}
service-account-issuer: {{ .serviceAccountIssuer }}
{{- end }}
{{- if .apiserverExtraArgs }}
{{ .apiserverExtraArgs.ToYaml | indent 10 }}
{{- end }}
Expand Down
3 changes: 3 additions & 0 deletions pkg/providers/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ func buildTemplateMapCP(clusterSpec *cluster.Spec) map[string]interface{} {
values["controlPlaneTaints"] = clusterSpec.Spec.ControlPlaneConfiguration.Taints
}

if clusterSpec.Spec.PodIAMConfig != nil {
values["serviceAccountIssuer"] = clusterSpec.Spec.PodIAMConfig.ServiceAccountIssuer
}
return values
}

Expand Down
35 changes: 35 additions & 0 deletions pkg/providers/docker/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,38 @@ func TestChangeDiffWithChange(t *testing.T) {

tt.Expect(tt.provider.ChangeDiff(clusterSpec, newClusterSpec)).To(Equal(wantDiff))
}

func TestProviderGenerateCAPISpecForCreateWithPodIAMConfig(t *testing.T) {
mockCtrl := gomock.NewController(t)
ctx := context.Background()
client := dockerMocks.NewMockProviderClient(mockCtrl)
kubectl := dockerMocks.NewMockProviderKubectlClient(mockCtrl)
provider := docker.NewProvider(&v1alpha1.DockerDatacenterConfig{}, client, kubectl, test.FakeNow)
clusterObj := &types.Cluster{
Name: "test-cluster",
}
clusterSpec := test.NewClusterSpec(func(s *cluster.Spec) {
s.Name = "test-cluster"
s.Spec.KubernetesVersion = "1.19"
s.Spec.ClusterNetwork.Pods.CidrBlocks = []string{"192.168.0.0/16"}
s.Spec.ClusterNetwork.Services.CidrBlocks = []string{"10.128.0.0/12"}
s.Spec.ControlPlaneConfiguration.Count = 1
s.VersionsBundle = versionsBundle
})
clusterSpec.Spec.PodIAMConfig = &v1alpha1.PodIAMConfig{ServiceAccountIssuer: "https://test"}

if provider == nil {
t.Fatalf("provider object is nil")
}

err := provider.SetupAndValidateCreateCluster(ctx, clusterSpec)
if err != nil {
t.Fatalf("failed to setup and validate: %v", err)
}

cp, _, err := provider.GenerateCAPISpecForCreate(context.Background(), clusterObj, clusterSpec)
if err != nil {
t.Fatalf("failed to generate cluster api spec contents: %v", err)
}
test.AssertContentToFile(t, string(cp), "testdata/valid_deployment_cp_pod_iam_expected.yaml")
}
Loading

0 comments on commit 05659db

Please sign in to comment.