|
1 | 1 | package aws
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "log" |
5 |
| - |
6 |
| - "github.com/hashicorp/hcl/v2" |
7 |
| - "github.com/terraform-linters/tflint-plugin-sdk/terraform/configs" |
| 4 | + "github.com/terraform-linters/tflint-plugin-sdk/hclext" |
8 | 5 | "github.com/terraform-linters/tflint-plugin-sdk/tflint"
|
9 | 6 | )
|
10 | 7 |
|
11 | 8 | // AwsProviderBlockSchema is a schema of `aws` provider block
|
12 |
| -var AwsProviderBlockSchema = &hcl.BodySchema{ |
13 |
| - Attributes: []hcl.AttributeSchema{ |
| 9 | +var AwsProviderBlockSchema = &hclext.BodySchema{ |
| 10 | + Attributes: []hclext.AttributeSchema{ |
14 | 11 | {Name: "access_key"},
|
15 | 12 | {Name: "secret_key"},
|
16 | 13 | {Name: "profile"},
|
17 | 14 | {Name: "shared_credentials_file"},
|
18 | 15 | {Name: "region"},
|
19 | 16 | },
|
20 |
| - Blocks: []hcl.BlockHeaderSchema{ |
21 |
| - {Type: "assume_role"}, |
| 17 | + Blocks: []hclext.BlockSchema{ |
| 18 | + { |
| 19 | + Type: "assume_role", |
| 20 | + Body: AwsProviderAssumeRoleBlockShema, |
| 21 | + }, |
22 | 22 | },
|
23 | 23 | }
|
24 | 24 |
|
25 | 25 | // AwsProviderAssumeRoleBlockShema is a schema of `assume_role` block
|
26 |
| -var AwsProviderAssumeRoleBlockShema = &hcl.BodySchema{ |
27 |
| - Attributes: []hcl.AttributeSchema{ |
| 26 | +var AwsProviderAssumeRoleBlockShema = &hclext.BodySchema{ |
| 27 | + Attributes: []hclext.AttributeSchema{ |
28 | 28 | {Name: "role_arn", Required: true},
|
29 | 29 | {Name: "session_name"},
|
30 | 30 | {Name: "external_id"},
|
31 | 31 | {Name: "policy"},
|
32 | 32 | },
|
33 | 33 | }
|
34 | 34 |
|
35 |
| -// ProviderData represents a provider block with an eval context (runner) |
36 |
| -type ProviderData struct { |
37 |
| - provider *configs.Provider |
38 |
| - runner tflint.Runner |
39 |
| - attributes hcl.Attributes |
40 |
| - blocks hcl.Blocks |
41 |
| -} |
42 |
| - |
43 | 35 | // GetCredentialsFromProvider retrieves credentials from the "provider" block in the Terraform configuration
|
44 | 36 | func GetCredentialsFromProvider(runner tflint.Runner) (Credentials, error) {
|
45 | 37 | creds := Credentials{}
|
46 | 38 |
|
47 |
| - providerConfig, err := runner.RootProvider("aws") |
48 |
| - if err != nil || providerConfig == nil { |
49 |
| - return creds, err |
50 |
| - } |
51 |
| - |
52 |
| - d, err := newProviderData(providerConfig, runner) |
53 |
| - if err != nil { |
54 |
| - return creds, err |
55 |
| - } |
56 |
| - |
57 |
| - accessKey, exists, err := d.Get("access_key") |
58 |
| - if err != nil { |
59 |
| - return creds, err |
60 |
| - } |
61 |
| - if exists { |
62 |
| - creds.AccessKey = accessKey |
63 |
| - } |
64 |
| - |
65 |
| - secretKey, exists, err := d.Get("secret_key") |
| 39 | + providers, err := runner.GetModuleContent( |
| 40 | + &hclext.BodySchema{ |
| 41 | + Blocks: []hclext.BlockSchema{ |
| 42 | + { |
| 43 | + Type: "provider", |
| 44 | + LabelNames: []string{"name"}, |
| 45 | + Body: AwsProviderBlockSchema, |
| 46 | + }, |
| 47 | + }, |
| 48 | + }, |
| 49 | + &tflint.GetModuleContentOption{ModuleCtx: tflint.RootModuleCtxType}, |
| 50 | + ) |
66 | 51 | if err != nil {
|
67 | 52 | return creds, err
|
68 | 53 | }
|
69 |
| - if exists { |
70 |
| - creds.SecretKey = secretKey |
71 |
| - } |
72 | 54 |
|
73 |
| - profile, exists, err := d.Get("profile") |
74 |
| - if err != nil { |
75 |
| - return creds, err |
76 |
| - } |
77 |
| - if exists { |
78 |
| - creds.Profile = profile |
79 |
| - } |
80 |
| - |
81 |
| - credsFile, exists, err := d.Get("shared_credentials_file") |
82 |
| - if err != nil { |
83 |
| - return creds, err |
84 |
| - } |
85 |
| - if exists { |
86 |
| - creds.CredsFile = credsFile |
87 |
| - } |
| 55 | + for _, provider := range providers.Blocks { |
| 56 | + if provider.Labels[0] != "aws" { |
| 57 | + continue |
| 58 | + } |
88 | 59 |
|
89 |
| - region, exists, err := d.Get("region") |
90 |
| - if err != nil { |
91 |
| - return creds, err |
92 |
| - } |
93 |
| - if exists { |
94 |
| - creds.Region = region |
95 |
| - } |
| 60 | + opts := &tflint.EvaluateExprOption{ModuleCtx: tflint.RootModuleCtxType} |
96 | 61 |
|
97 |
| - assumeRole, exists, err := d.GetBlock("assume_role", AwsProviderAssumeRoleBlockShema) |
98 |
| - if err != nil { |
99 |
| - return creds, err |
100 |
| - } |
101 |
| - if exists { |
102 |
| - roleARN, exists, err := assumeRole.Get("role_arn") |
103 |
| - if err != nil { |
104 |
| - return creds, err |
105 |
| - } |
106 |
| - if exists { |
107 |
| - creds.AssumeRoleARN = roleARN |
| 62 | + if attr, exists := provider.Body.Attributes["access_key"]; exists { |
| 63 | + if err := runner.EvaluateExpr(attr.Expr, &creds.AccessKey, opts); err != nil { |
| 64 | + return creds, err |
| 65 | + } |
108 | 66 | }
|
109 | 67 |
|
110 |
| - sessionName, exists, err := assumeRole.Get("session_name") |
111 |
| - if err != nil { |
112 |
| - return creds, err |
113 |
| - } |
114 |
| - if exists { |
115 |
| - creds.AssumeRoleSessionName = sessionName |
| 68 | + if attr, exists := provider.Body.Attributes["secret_key"]; exists { |
| 69 | + if err := runner.EvaluateExpr(attr.Expr, &creds.SecretKey, opts); err != nil { |
| 70 | + return creds, err |
| 71 | + } |
116 | 72 | }
|
117 | 73 |
|
118 |
| - externalID, exists, err := assumeRole.Get("external_id") |
119 |
| - if err != nil { |
120 |
| - return creds, err |
121 |
| - } |
122 |
| - if exists { |
123 |
| - creds.AssumeRoleExternalID = externalID |
| 74 | + if attr, exists := provider.Body.Attributes["profile"]; exists { |
| 75 | + if err := runner.EvaluateExpr(attr.Expr, &creds.Profile, opts); err != nil { |
| 76 | + return creds, err |
| 77 | + } |
124 | 78 | }
|
125 | 79 |
|
126 |
| - policy, exists, err := assumeRole.Get("policy") |
127 |
| - if err != nil { |
128 |
| - return creds, err |
129 |
| - } |
130 |
| - if exists { |
131 |
| - creds.AssumeRolePolicy = policy |
| 80 | + if attr, exists := provider.Body.Attributes["shared_credentials_file"]; exists { |
| 81 | + if err := runner.EvaluateExpr(attr.Expr, &creds.CredsFile, opts); err != nil { |
| 82 | + return creds, err |
| 83 | + } |
132 | 84 | }
|
133 |
| - } |
134 | 85 |
|
135 |
| - return creds, nil |
136 |
| -} |
137 |
| - |
138 |
| -func newProviderData(provider *configs.Provider, runner tflint.Runner) (*ProviderData, error) { |
139 |
| - providerData := &ProviderData{ |
140 |
| - provider: provider, |
141 |
| - runner: runner, |
142 |
| - attributes: map[string]*hcl.Attribute{}, |
143 |
| - blocks: []*hcl.Block{}, |
144 |
| - } |
145 |
| - |
146 |
| - if provider != nil { |
147 |
| - content, _, diags := provider.Config.PartialContent(AwsProviderBlockSchema) |
148 |
| - if diags.HasErrors() { |
149 |
| - return nil, diags |
| 86 | + if attr, exists := provider.Body.Attributes["region"]; exists { |
| 87 | + if err := runner.EvaluateExpr(attr.Expr, &creds.Region, opts); err != nil { |
| 88 | + return creds, err |
| 89 | + } |
150 | 90 | }
|
151 | 91 |
|
152 |
| - providerData.attributes = content.Attributes |
153 |
| - providerData.blocks = content.Blocks |
154 |
| - } |
155 |
| - |
156 |
| - return providerData, nil |
157 |
| -} |
158 |
| - |
159 |
| -// Get returns a value corresponding to the given key |
160 |
| -// It should be noted that the value is evaluated if it is evaluable |
161 |
| -// The second return value is a flag that determines whether a value exists |
162 |
| -// We assume the provider has only simple attributes, so it just returns string |
163 |
| -func (d *ProviderData) Get(key string) (string, bool, error) { |
164 |
| - attribute, exists := d.attributes[key] |
165 |
| - if !exists { |
166 |
| - log.Printf("[INFO] `%s` is not found in the provider block.", key) |
167 |
| - return "", false, nil |
168 |
| - } |
169 |
| - |
170 |
| - var val string |
171 |
| - err := d.runner.EvaluateExprOnRootCtx(attribute.Expr, &val, nil) |
172 |
| - |
173 |
| - err = d.runner.EnsureNoError(err, func() error { return nil }) |
174 |
| - if err != nil { |
175 |
| - return "", true, err |
176 |
| - } |
177 |
| - return val, true, nil |
178 |
| -} |
179 |
| - |
180 |
| -// GetBlock returns a value just like Get. |
181 |
| -// The difference is that GetBlock returns ProviderData rather than a string value. |
182 |
| -func (d *ProviderData) GetBlock(key string, schema *hcl.BodySchema) (*ProviderData, bool, error) { |
183 |
| - providerData := &ProviderData{ |
184 |
| - provider: d.provider, |
185 |
| - runner: d.runner, |
186 |
| - attributes: map[string]*hcl.Attribute{}, |
187 |
| - blocks: []*hcl.Block{}, |
188 |
| - } |
189 |
| - |
190 |
| - var ret *hcl.Block |
191 |
| - for _, block := range d.blocks { |
192 |
| - if block.Type == key { |
193 |
| - ret = block |
| 92 | + for _, assumeRole := range provider.Body.Blocks { |
| 93 | + if attr, exists := assumeRole.Body.Attributes["role_arn"]; exists { |
| 94 | + if err := runner.EvaluateExpr(attr.Expr, &creds.AssumeRoleARN, opts); err != nil { |
| 95 | + return creds, err |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + if attr, exists := assumeRole.Body.Attributes["session_name"]; exists { |
| 100 | + if err := runner.EvaluateExpr(attr.Expr, &creds.AssumeRoleSessionName, opts); err != nil { |
| 101 | + return creds, err |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + if attr, exists := assumeRole.Body.Attributes["external_id"]; exists { |
| 106 | + if err := runner.EvaluateExpr(attr.Expr, &creds.AssumeRoleExternalID, opts); err != nil { |
| 107 | + return creds, err |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + if attr, exists := assumeRole.Body.Attributes["policy"]; exists { |
| 112 | + if err := runner.EvaluateExpr(attr.Expr, &creds.AssumeRolePolicy, opts); err != nil { |
| 113 | + return creds, err |
| 114 | + } |
| 115 | + } |
194 | 116 | }
|
195 | 117 | }
|
196 |
| - if ret == nil { |
197 |
| - log.Printf("[INFO] `%s` is not found in the provider block.", key) |
198 |
| - return providerData, false, nil |
199 |
| - } |
200 | 118 |
|
201 |
| - content, _, diags := ret.Body.PartialContent(schema) |
202 |
| - if diags.HasErrors() { |
203 |
| - return providerData, true, diags |
204 |
| - } |
205 |
| - |
206 |
| - providerData.attributes = content.Attributes |
207 |
| - providerData.blocks = content.Blocks |
208 |
| - |
209 |
| - return providerData, true, nil |
| 119 | + return creds, nil |
210 | 120 | }
|
0 commit comments