sigs.k8s.io/cluster-api-provider-aws@v1.5.5/cmd/clusterawsadm/cloudformation/bootstrap/template.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package bootstrap 18 19 import ( 20 "fmt" 21 22 "github.com/awslabs/goformation/v4/cloudformation" 23 cfn_iam "github.com/awslabs/goformation/v4/cloudformation/iam" 24 25 bootstrapv1 "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/api/bootstrap/v1beta1" 26 "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/converters" 27 ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1" 28 expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/exp/api/v1beta1" 29 iamv1 "sigs.k8s.io/cluster-api-provider-aws/iam/api/v1beta1" 30 eksiam "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/eks/iam" 31 ) 32 33 // Constants that define resources for a Template. 34 const ( 35 AWSIAMGroupBootstrapper = "AWSIAMGroupBootstrapper" 36 AWSIAMInstanceProfileControllers = "AWSIAMInstanceProfileControllers" 37 AWSIAMInstanceProfileControlPlane = "AWSIAMInstanceProfileControlPlane" 38 AWSIAMInstanceProfileNodes = "AWSIAMInstanceProfileNodes" 39 AWSIAMRoleControllers = "AWSIAMRoleControllers" 40 AWSIAMRoleControlPlane = "AWSIAMRoleControlPlane" 41 AWSIAMRoleNodes = "AWSIAMRoleNodes" 42 AWSIAMRoleEKSControlPlane = "AWSIAMRoleEKSControlPlane" 43 AWSIAMRoleEKSNodegroup = "AWSIAMRoleEKSNodegroup" 44 AWSIAMRoleEKSFargate = "AWSIAMRoleEKSFargate" 45 AWSIAMUserBootstrapper = "AWSIAMUserBootstrapper" 46 ControllersPolicy PolicyName = "AWSIAMManagedPolicyControllers" 47 ControllersPolicyEKS PolicyName = "AWSIAMManagedPolicyControllersEKS" 48 ControlPlanePolicy PolicyName = "AWSIAMManagedPolicyCloudProviderControlPlane" 49 NodePolicy PolicyName = "AWSIAMManagedPolicyCloudProviderNodes" 50 CSIPolicy PolicyName = "AWSEBSCSIPolicyController" 51 EKSConsolePolicy PolicyName = "AWSIAMManagedPolicyEKSConsole" 52 ) 53 54 // Template is an AWS CloudFormation template to bootstrap 55 // IAM policies, users and roles for use by Cluster API Provider AWS. 56 type Template struct { 57 Spec *bootstrapv1.AWSIAMConfigurationSpec 58 } 59 60 // NewTemplate will generate a new Template. 61 func NewTemplate() Template { 62 conf := bootstrapv1.NewAWSIAMConfiguration() 63 return Template{ 64 Spec: &conf.Spec, 65 } 66 } 67 68 // NewManagedName creates an IAM acceptable name prefixed with this Cluster API 69 // implementation's prefix. 70 func (t Template) NewManagedName(name string) string { 71 return fmt.Sprintf("%s%s%s", t.Spec.NamePrefix, name, *t.Spec.NameSuffix) 72 } 73 74 // RenderCloudFormation will render and return a cloudformation Template. 75 func (t Template) RenderCloudFormation() *cloudformation.Template { 76 template := cloudformation.NewTemplate() 77 78 if t.Spec.BootstrapUser.Enable { 79 template.Resources[AWSIAMUserBootstrapper] = &cfn_iam.User{ 80 UserName: t.Spec.BootstrapUser.UserName, 81 Groups: t.bootstrapUserGroups(), 82 ManagedPolicyArns: t.Spec.ControlPlane.ExtraPolicyAttachments, 83 Policies: t.bootstrapUserPolicy(), 84 Tags: converters.MapToCloudFormationTags(t.Spec.BootstrapUser.Tags), 85 } 86 87 template.Resources[AWSIAMGroupBootstrapper] = &cfn_iam.Group{ 88 GroupName: t.Spec.BootstrapUser.GroupName, 89 } 90 } 91 92 template.Resources[string(ControllersPolicy)] = &cfn_iam.ManagedPolicy{ 93 ManagedPolicyName: t.NewManagedName("controllers"), 94 Description: `For the Kubernetes Cluster API Provider AWS Controllers`, 95 PolicyDocument: t.ControllersPolicy(), 96 Groups: t.controllersPolicyGroups(), 97 Roles: t.controllersPolicyRoleAttachments(), 98 } 99 100 if !t.Spec.EKS.Disable { 101 template.Resources[string(ControllersPolicyEKS)] = &cfn_iam.ManagedPolicy{ 102 ManagedPolicyName: t.NewManagedName("controllers-eks"), 103 Description: `For the Kubernetes Cluster API Provider AWS Controllers`, 104 PolicyDocument: t.ControllersPolicyEKS(), 105 Groups: t.controllersPolicyGroups(), 106 Roles: t.controllersPolicyRoleAttachments(), 107 } 108 } 109 110 if !t.Spec.ControlPlane.DisableCloudProviderPolicy { 111 template.Resources[string(ControlPlanePolicy)] = &cfn_iam.ManagedPolicy{ 112 ManagedPolicyName: t.NewManagedName("control-plane"), 113 Description: `For the Kubernetes Cloud Provider AWS Control Plane`, 114 PolicyDocument: t.cloudProviderControlPlaneAwsPolicy(), 115 Roles: t.cloudProviderControlPlaneAwsRoles(), 116 } 117 } 118 119 if !t.Spec.Nodes.DisableCloudProviderPolicy { 120 template.Resources[string(NodePolicy)] = &cfn_iam.ManagedPolicy{ 121 ManagedPolicyName: t.NewManagedName("nodes"), 122 Description: `For the Kubernetes Cloud Provider AWS nodes`, 123 PolicyDocument: t.nodePolicy(), 124 Roles: t.cloudProviderNodeAwsRoles(), 125 } 126 } 127 128 if t.Spec.ControlPlane.EnableCSIPolicy { 129 template.Resources[string(CSIPolicy)] = &cfn_iam.ManagedPolicy{ 130 ManagedPolicyName: t.NewManagedName("csi"), 131 Description: `For the AWS EBS CSI Driver for Kubernetes`, 132 PolicyDocument: t.csiControllerPolicy(), 133 Roles: t.csiControlPlaneAwsRoles(), 134 } 135 } 136 137 template.Resources[AWSIAMRoleControlPlane] = &cfn_iam.Role{ 138 RoleName: t.NewManagedName("control-plane"), 139 AssumeRolePolicyDocument: t.controlPlaneTrustPolicy(), 140 ManagedPolicyArns: t.Spec.ControlPlane.ExtraPolicyAttachments, 141 Policies: t.controlPlanePolicies(), 142 Tags: converters.MapToCloudFormationTags(t.Spec.ControlPlane.Tags), 143 } 144 145 template.Resources[AWSIAMRoleControllers] = &cfn_iam.Role{ 146 RoleName: t.NewManagedName("controllers"), 147 AssumeRolePolicyDocument: t.controllersTrustPolicy(), 148 Policies: t.controllersRolePolicy(), 149 Tags: converters.MapToCloudFormationTags(t.Spec.ClusterAPIControllers.Tags), 150 } 151 152 template.Resources[AWSIAMRoleNodes] = &cfn_iam.Role{ 153 RoleName: t.NewManagedName("nodes"), 154 AssumeRolePolicyDocument: t.nodeTrustPolicy(), 155 ManagedPolicyArns: t.nodeManagedPolicies(), 156 Policies: t.nodePolicies(), 157 Tags: converters.MapToCloudFormationTags(t.Spec.Nodes.Tags), 158 } 159 160 template.Resources[AWSIAMInstanceProfileControlPlane] = &cfn_iam.InstanceProfile{ 161 InstanceProfileName: t.NewManagedName("control-plane"), 162 Roles: []string{ 163 cloudformation.Ref(AWSIAMRoleControlPlane), 164 }, 165 } 166 167 template.Resources[AWSIAMInstanceProfileControllers] = &cfn_iam.InstanceProfile{ 168 InstanceProfileName: t.NewManagedName("controllers"), 169 Roles: []string{ 170 cloudformation.Ref(AWSIAMRoleControllers), 171 }, 172 } 173 174 template.Resources[AWSIAMInstanceProfileNodes] = &cfn_iam.InstanceProfile{ 175 InstanceProfileName: t.NewManagedName("nodes"), 176 Roles: []string{ 177 cloudformation.Ref(AWSIAMRoleNodes), 178 }, 179 } 180 181 if !t.Spec.EKS.DefaultControlPlaneRole.Disable && !t.Spec.EKS.Disable { 182 template.Resources[AWSIAMRoleEKSControlPlane] = &cfn_iam.Role{ 183 RoleName: ekscontrolplanev1.DefaultEKSControlPlaneRole, 184 AssumeRolePolicyDocument: AssumeRolePolicy(iamv1.PrincipalService, []string{"eks.amazonaws.com"}), 185 ManagedPolicyArns: t.eksControlPlanePolicies(), 186 Tags: converters.MapToCloudFormationTags(t.Spec.EKS.DefaultControlPlaneRole.Tags), 187 } 188 } 189 190 if !t.Spec.EKS.ManagedMachinePool.Disable && !t.Spec.EKS.Disable { 191 template.Resources[AWSIAMRoleEKSNodegroup] = &cfn_iam.Role{ 192 RoleName: expinfrav1.DefaultEKSNodegroupRole, 193 AssumeRolePolicyDocument: AssumeRolePolicy(iamv1.PrincipalService, []string{"ec2.amazonaws.com", "eks.amazonaws.com"}), 194 ManagedPolicyArns: t.eksMachinePoolPolicies(), 195 Tags: converters.MapToCloudFormationTags(t.Spec.EKS.ManagedMachinePool.Tags), 196 } 197 } 198 199 if !t.Spec.EKS.Fargate.Disable && !t.Spec.EKS.Disable { 200 template.Resources[AWSIAMRoleEKSFargate] = &cfn_iam.Role{ 201 RoleName: expinfrav1.DefaultEKSFargateRole, 202 AssumeRolePolicyDocument: AssumeRolePolicy(iamv1.PrincipalService, []string{eksiam.EKSFargateService}), 203 ManagedPolicyArns: fargateProfilePolicies(t.Spec.EKS.Fargate), 204 Tags: converters.MapToCloudFormationTags(t.Spec.EKS.Fargate.Tags), 205 } 206 } 207 208 if t.Spec.EKS.EnableUserEKSConsolePolicy && !t.Spec.EKS.Disable { 209 template.Resources[string(EKSConsolePolicy)] = &cfn_iam.ManagedPolicy{ 210 ManagedPolicyName: t.NewManagedName("eks-console"), 211 Description: `For users/groups to view EKS nodes and workloads`, 212 PolicyDocument: t.eksConsolePolicies(), 213 } 214 } 215 216 return template 217 } 218 219 func ec2AssumeRolePolicy() *iamv1.PolicyDocument { 220 return AssumeRolePolicy(iamv1.PrincipalService, []string{"ec2.amazonaws.com"}) 221 } 222 223 // AWSArnAssumeRolePolicy will assume Policies using PolicyArns. 224 func AWSArnAssumeRolePolicy(identityID string) *iamv1.PolicyDocument { 225 return AssumeRolePolicy(iamv1.PrincipalAWS, []string{identityID}) 226 } 227 228 // AWSServiceAssumeRolePolicy will assume an AWS Service policy. 229 func AWSServiceAssumeRolePolicy(identityID string) *iamv1.PolicyDocument { 230 return AssumeRolePolicy(iamv1.PrincipalService, []string{identityID}) 231 } 232 233 // AssumeRolePolicy will create a role session and pass session policies programmatically. 234 func AssumeRolePolicy(identityType iamv1.PrincipalType, principalIDs []string) *iamv1.PolicyDocument { 235 return &iamv1.PolicyDocument{ 236 Version: iamv1.CurrentVersion, 237 Statement: []iamv1.StatementEntry{ 238 { 239 Effect: iamv1.EffectAllow, 240 Principal: iamv1.Principals{identityType: principalIDs}, 241 Action: iamv1.Actions{"sts:AssumeRole"}, 242 }, 243 }, 244 } 245 }