-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
fargate.go
132 lines (112 loc) · 4.17 KB
/
fargate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package builder
import (
"fmt"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
gfniam "github.com/weaveworks/goformation/v4/cloudformation/iam"
gfnt "github.com/weaveworks/goformation/v4/cloudformation/types"
api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5"
"github.com/weaveworks/eksctl/pkg/cfn/outputs"
cft "github.com/weaveworks/eksctl/pkg/cfn/template"
)
const (
fargateTemplateDescription = "Fargate IAM"
fargateRoleName = "FargatePodExecutionRole"
fargateRoleDescription = "EKS Fargate pod execution IAM role [created by eksctl]"
)
// FargateResourceSet manages only fargate resources
type FargateResourceSet struct {
rs *resourceSet
spec *api.ClusterConfig
}
// NewFargateResourceSet returns a resource set for managing fargate resources
func NewFargateResourceSet(spec *api.ClusterConfig) *FargateResourceSet {
rs := newResourceSet()
rs.withIAM = true
rs.withNamedIAM = true
return &FargateResourceSet{
rs,
spec,
}
}
func (rs *FargateResourceSet) AddAllResources() error {
rs.rs.template.Mappings[servicePrincipalPartitionMapName] = api.Partitions.ServicePrincipalPartitionMappings()
rs.rs.template.Description = fmt.Sprintf(
"%s %s",
fargateTemplateDescription,
templateDescriptionSuffix,
)
return addResourcesForFargate(rs.rs, rs.spec)
}
func (rs *FargateResourceSet) WithIAM() bool {
return true
}
func (rs *FargateResourceSet) WithNamedIAM() bool {
return true
}
func (rs *FargateResourceSet) RenderJSON() ([]byte, error) {
return rs.rs.renderJSON()
}
func (rs *FargateResourceSet) GetAllOutputs(stack types.Stack) error {
return rs.rs.GetAllOutputs(stack)
}
// addResourcesForFargate adds resources for Fargate.
func addResourcesForFargate(rs *resourceSet, cfg *api.ClusterConfig) error {
if api.IsSetAndNonEmptyString(cfg.IAM.FargatePodExecutionRoleARN) {
rs.defineOutputWithoutCollector(outputs.FargatePodExecutionRoleARN, cfg.IAM.FargatePodExecutionRoleARN, true)
return nil
}
// Create a role requires additional capabilities.
// If not set to true, CloudFormation fails with:
// status code 400: InsufficientCapabilitiesException: Requires capabilities : [CAPABILITY_IAM]
rs.withIAM = true
rs.template.Description = fargateRoleDescription
// As per AWS docs, to avoid a confused deputy security problem, it's important that the role restricts access based on SourceArn.
// See: https://docs.aws.amazon.com/eks/latest/userguide/pod-execution-role.html#check-pod-execution-role
sourceArnCondition, err := makeSourceArnCondition(cfg)
if err != nil {
return fmt.Errorf("restricting access based on SourceArn: %w", err)
}
role := &gfniam.Role{
AssumeRolePolicyDocument: cft.MakeAssumeRolePolicyDocumentForServicesWithConditions(
sourceArnCondition,
MakeServiceRef("EKSFargatePods"), // Ensure that EKS can schedule pods onto Fargate.
),
ManagedPolicyArns: gfnt.NewSlice(makePolicyARNs(
iamPolicyAmazonEKSFargatePodExecutionRolePolicy,
)...),
}
if api.IsSetAndNonEmptyString(cfg.IAM.FargatePodExecutionRolePermissionsBoundary) {
role.PermissionsBoundary = gfnt.NewString(*cfg.IAM.FargatePodExecutionRolePermissionsBoundary)
}
rs.newResource(fargateRoleName, role)
rs.defineOutputFromAtt(outputs.FargatePodExecutionRoleARN, fargateRoleName, "Arn", true, func(v string) error {
cfg.IAM.FargatePodExecutionRoleARN = &v
return nil
})
return nil
}
func makeSourceArnCondition(cfg *api.ClusterConfig) (cft.MapOfInterfaces, error) {
accountID, err := getAWSAccountID(cfg)
if err != nil {
return nil, err
}
return cft.MapOfInterfaces{
"ArnLike": cft.MapOfInterfaces{
"aws:SourceArn": fmt.Sprintf("arn:%s:eks:%s:%s:fargateprofile/%s/*", api.Partitions.ForRegion(cfg.Metadata.Region), cfg.Metadata.Region, accountID, cfg.Metadata.Name),
},
}, nil
}
func getAWSAccountID(cfg *api.ClusterConfig) (string, error) {
if cfg.Metadata.AccountID != "" {
return cfg.Metadata.AccountID, nil
}
if cfg.Status != nil && cfg.Status.ARN != "" {
parsedARN, err := arn.Parse(cfg.Status.ARN)
if err != nil {
return "", fmt.Errorf("error parsing cluster ARN: %v", err)
}
return parsedARN.AccountID, nil
}
return "", fmt.Errorf("failed to determine account ID")
}