sigs.k8s.io/cluster-api-provider-aws@v1.5.5/test/e2e/shared/template.go (about) 1 //go:build e2e 2 // +build e2e 3 4 /* 5 Copyright 2020 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package shared 21 22 import ( 23 "context" 24 "os" 25 "path" 26 27 "github.com/awslabs/goformation/v4/cloudformation" 28 cfn_iam "github.com/awslabs/goformation/v4/cloudformation/iam" 29 . "github.com/onsi/ginkgo" 30 . "github.com/onsi/gomega" 31 "gopkg.in/yaml.v2" 32 33 infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" 34 bootstrapv1 "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/api/bootstrap/v1beta1" 35 cfn_bootstrap "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/cloudformation/bootstrap" 36 "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/credentials" 37 iamv1 "sigs.k8s.io/cluster-api-provider-aws/iam/api/v1beta1" 38 "sigs.k8s.io/cluster-api/test/framework" 39 "sigs.k8s.io/cluster-api/test/framework/clusterctl" 40 ) 41 42 const ( 43 // MultiTenancyJumpPolicy is the policy name for jump host to be used in multi-tenancy test. 44 MultiTenancyJumpPolicy = "CAPAMultiTenancyJumpPolicy" 45 ) 46 47 var ( 48 accountRef = cloudformation.Sub("arn:${AWS::Partition}:iam::${AWS::AccountId}:root") 49 ) 50 51 // newBootstrapTemplate generates a clusterawsadm configuration, and prints it 52 // and the resultant cloudformation template to the artifacts directory. 53 func newBootstrapTemplate(e2eCtx *E2EContext) *cfn_bootstrap.Template { 54 By("Creating a bootstrap AWSIAMConfiguration") 55 t := cfn_bootstrap.NewTemplate() 56 t.Spec.BootstrapUser.Enable = true 57 t.Spec.BootstrapUser.ExtraStatements = []iamv1.StatementEntry{ 58 { 59 Effect: iamv1.EffectAllow, 60 Resource: iamv1.Resources{ 61 iamv1.Any, 62 }, 63 Action: iamv1.Actions{ 64 "ecr-public:*", 65 "sts:*", 66 "servicequotas:GetServiceQuota", 67 "servicequotas:RequestServiceQuotaIncrease", 68 "servicequotas:ListRequestedServiceQuotaChangeHistory", 69 "elasticloadbalancing:DescribeAccountLimits", 70 "ec2:DescribeAccountLimits", 71 "cloudtrail:LookupEvents", 72 "ssm:StartSession", 73 "ssm:DescribeSessions", 74 "ssm:GetConnectionStatus", 75 "ssm:DescribeInstanceProperties", 76 "ssm:GetDocument", 77 "ssm:TerminateSession", 78 "ssm:ResumeSession", 79 "ec2:DescribeSubnets", 80 "ec2:DescribeNetworkInterfaces", 81 "ec2:CreateNetworkInterface", 82 "ec2:DescribeAvailabilityZones", 83 "ec2:DeleteNetworkInterface", 84 "elasticfilesystem:DescribeMountTargets", 85 "elasticfilesystem:CreateMountTarget", 86 "elasticfilesystem:DeleteMountTarget", 87 "elasticfilesystem:DescribeFileSystems", 88 "elasticfilesystem:CreateFileSystem", 89 "elasticfilesystem:DeleteFileSystem", 90 "elasticfilesystem:DescribeAccessPoints", 91 "elasticfilesystem:CreateAccessPoint", 92 "elasticfilesystem:DeleteAccessPoint", 93 }, 94 }, 95 { 96 Effect: iamv1.EffectAllow, 97 Resource: iamv1.Resources{ 98 "arn:*:iam::*:role/aws-service-role/servicequotas.amazonaws.com/AWSServiceRoleForServiceQuotas", 99 "arn:*:iam::*:role/aws-service-role/support.amazonaws.com/AWSServiceRoleForSupport", 100 "arn:*:iam::*:role/aws-service-role/trustedadvisor.amazonaws.com/AWSServiceRoleForTrustedAdvisor", 101 }, 102 Action: iamv1.Actions{ 103 "iam:CreateServiceLinkedRole", 104 }, 105 }, 106 } 107 t.Spec.SecureSecretsBackends = []infrav1.SecretBackend{ 108 infrav1.SecretBackendSecretsManager, 109 infrav1.SecretBackendSSMParameterStore, 110 } 111 t.Spec.EventBridge = &bootstrapv1.EventBridgeConfig{ 112 Enable: true, 113 } 114 115 region, err := credentials.ResolveRegion("") 116 Expect(err).NotTo(HaveOccurred()) 117 t.Spec.Region = region 118 t.Spec.EKS.Disable = false 119 t.Spec.EKS.AllowIAMRoleCreation = false 120 t.Spec.EKS.DefaultControlPlaneRole.Disable = false 121 t.Spec.EKS.ManagedMachinePool.Disable = false 122 t.Spec.S3Buckets.Enable = true 123 t.Spec.Nodes.ExtraStatements = []iamv1.StatementEntry{ 124 { 125 Effect: iamv1.EffectAllow, 126 Resource: iamv1.Resources{ 127 iamv1.Any, 128 }, 129 Action: iamv1.Actions{ 130 "elasticfilesystem:DescribeMountTargets", 131 "elasticfilesystem:DeleteAccessPoint", 132 "elasticfilesystem:DescribeAccessPoints", 133 "elasticfilesystem:DescribeFileSystems", 134 "elasticfilesystem:CreateAccessPoint", 135 "ec2:DescribeAvailabilityZones", 136 }, 137 }, 138 } 139 str, err := yaml.Marshal(t.Spec) 140 Expect(err).NotTo(HaveOccurred()) 141 Expect(os.WriteFile(path.Join(e2eCtx.Settings.ArtifactFolder, "awsiamconfiguration.yaml"), str, 0644)).To(Succeed()) //nolint:gosec 142 cloudformationTemplate := renderCustomCloudFormation(&t) 143 cfnData, err := cloudformationTemplate.YAML() 144 Expect(err).NotTo(HaveOccurred()) 145 Expect(os.WriteFile(path.Join(e2eCtx.Settings.ArtifactFolder, "cloudformation.yaml"), cfnData, 0644)).To(Succeed()) //nolint:gosec 146 return &t 147 } 148 149 func renderCustomCloudFormation(t *cfn_bootstrap.Template) *cloudformation.Template { 150 cloudformationTemplate := t.RenderCloudFormation() 151 appendMultiTenancyRoles(t, cloudformationTemplate) 152 return cloudformationTemplate 153 } 154 155 func appendMultiTenancyRoles(t *cfn_bootstrap.Template, cfnt *cloudformation.Template) { 156 controllersPolicy := cfnt.Resources[string(cfn_bootstrap.ControllersPolicy)].(*cfn_iam.ManagedPolicy) 157 controllersPolicy.Roles = append( 158 controllersPolicy.Roles, 159 cloudformation.Ref(MultiTenancySimpleRole.RoleName()), 160 cloudformation.Ref(MultiTenancyNestedRole.RoleName()), 161 ) 162 cfnt.Resources[MultiTenancyJumpPolicy] = &cfn_iam.ManagedPolicy{ 163 ManagedPolicyName: MultiTenancyJumpPolicy, 164 PolicyDocument: &iamv1.PolicyDocument{ 165 Version: iamv1.CurrentVersion, 166 Statement: []iamv1.StatementEntry{ 167 { 168 Effect: iamv1.EffectAllow, 169 Resource: iamv1.Resources{cloudformation.GetAtt(MultiTenancyNestedRole.RoleName(), "Arn")}, 170 Action: iamv1.Actions{"sts:AssumeRole"}, 171 }, 172 }, 173 }, 174 Roles: []string{cloudformation.Ref(MultiTenancyJumpRole.RoleName())}, 175 } 176 177 cfnt.Resources[MultiTenancySimpleRole.RoleName()] = &cfn_iam.Role{ 178 RoleName: MultiTenancySimpleRole.RoleName(), 179 AssumeRolePolicyDocument: cfn_bootstrap.AssumeRolePolicy(iamv1.PrincipalAWS, []string{accountRef}), 180 } 181 cfnt.Resources[MultiTenancyJumpRole.RoleName()] = &cfn_iam.Role{ 182 RoleName: MultiTenancyJumpRole.RoleName(), 183 AssumeRolePolicyDocument: cfn_bootstrap.AssumeRolePolicy(iamv1.PrincipalAWS, []string{accountRef}), 184 } 185 cfnt.Resources[MultiTenancyNestedRole.RoleName()] = &cfn_iam.Role{ 186 RoleName: MultiTenancyNestedRole.RoleName(), 187 AssumeRolePolicyDocument: cfn_bootstrap.AssumeRolePolicy(iamv1.PrincipalAWS, []string{accountRef}), 188 } 189 } 190 191 // getBootstrapTemplate gets or generates a new bootstrap template. 192 func getBootstrapTemplate(e2eCtx *E2EContext) *cfn_bootstrap.Template { 193 if e2eCtx.Environment.BootstrapTemplate == nil { 194 e2eCtx.Environment.BootstrapTemplate = newBootstrapTemplate(e2eCtx) 195 } 196 return e2eCtx.Environment.BootstrapTemplate 197 } 198 199 // ApplyTemplate will render a cluster template and apply it to the management cluster. 200 func ApplyTemplate(ctx context.Context, configCluster clusterctl.ConfigClusterInput, clusterProxy framework.ClusterProxy) error { 201 Expect(ctx).NotTo(BeNil(), "ctx is required for ApplyClusterTemplateAndWait") 202 203 Byf("Getting the cluster template yaml") 204 workloadClusterTemplate := clusterctl.ConfigCluster(ctx, clusterctl.ConfigClusterInput{ 205 KubeconfigPath: configCluster.KubeconfigPath, 206 ClusterctlConfigPath: configCluster.ClusterctlConfigPath, 207 Flavor: configCluster.Flavor, 208 Namespace: configCluster.Namespace, 209 ClusterName: configCluster.ClusterName, 210 KubernetesVersion: configCluster.KubernetesVersion, 211 ControlPlaneMachineCount: configCluster.ControlPlaneMachineCount, 212 WorkerMachineCount: configCluster.WorkerMachineCount, 213 InfrastructureProvider: configCluster.InfrastructureProvider, 214 LogFolder: configCluster.LogFolder, 215 }) 216 Expect(workloadClusterTemplate).ToNot(BeNil(), "Failed to get the cluster template") 217 218 Byf("Applying the %s cluster template yaml to the cluster", configCluster.Flavor) 219 return clusterProxy.Apply(ctx, workloadClusterTemplate) 220 }