|
13 | 13 | Output,
|
14 | 14 | Ref,
|
15 | 15 | Split,
|
| 16 | + Condition, |
16 | 17 | )
|
17 | 18 | from troposphere.certificatemanager import Certificate, DomainValidationOption
|
18 | 19 | from troposphere.cloudfront import (
|
|
43 | 44 | use_cmk_arn
|
44 | 45 | )
|
45 | 46 | from .domain import domain_name, domain_name_alternates, no_alt_domains
|
| 47 | +from .sftp import use_sftp_condition, use_sftp_with_kms_condition |
46 | 48 | from .template import template
|
47 | 49 | from .utils import ParameterWithDefaults as Parameter
|
48 | 50 |
|
|
122 | 124 |
|
123 | 125 |
|
124 | 126 | # Output S3 asset bucket name
|
125 |
| -template.add_output(Output( |
126 |
| - "AssetsBucketDomainName", |
127 |
| - Description="Assets bucket domain name", |
128 |
| - Value=GetAtt(assets_bucket, "DomainName") |
129 |
| -)) |
| 127 | +template.add_output( |
| 128 | + Output( |
| 129 | + "AssetsBucketDomainName", |
| 130 | + Description="Assets bucket domain name", |
| 131 | + Value=GetAtt(assets_bucket, "DomainName"), |
| 132 | + ) |
| 133 | +) |
130 | 134 |
|
131 | 135 |
|
132 | 136 | # Create an S3 bucket that holds user uploads or other non-public files
|
|
158 | 162 | )
|
159 | 163 | )
|
160 | 164 |
|
| 165 | +# Output S3 private assets bucket name |
| 166 | +template.add_output( |
| 167 | + Output( |
| 168 | + "PrivateAssetsBucketDomainName", |
| 169 | + Description="Private assets bucket domain name", |
| 170 | + Value=GetAtt(private_assets_bucket, "DomainName"), |
| 171 | + ) |
| 172 | +) |
161 | 173 |
|
162 |
| -# Output S3 asset bucket name |
163 |
| -template.add_output(Output( |
164 |
| - "PrivateAssetsBucketDomainName", |
165 |
| - Description="Private assets bucket domain name", |
166 |
| - Value=GetAtt(private_assets_bucket, "DomainName") |
167 |
| -)) |
| 174 | +# Bucket for SFTP service |
| 175 | +sftp_assets_bucket = Bucket( |
| 176 | + "SFTPAssetsBucket", |
| 177 | + Condition=use_sftp_condition, |
| 178 | + AccessControl=Private, |
| 179 | + PublicAccessBlockConfiguration=PublicAccessBlockConfiguration( |
| 180 | + BlockPublicAcls=True, |
| 181 | + BlockPublicPolicy=True, |
| 182 | + IgnorePublicAcls=True, |
| 183 | + RestrictPublicBuckets=True, |
| 184 | + ), |
| 185 | + BucketEncryption=If( |
| 186 | + use_aes256_encryption_cond, |
| 187 | + BucketEncryption( |
| 188 | + ServerSideEncryptionConfiguration=[ |
| 189 | + ServerSideEncryptionRule( |
| 190 | + ServerSideEncryptionByDefault=ServerSideEncryptionByDefault( |
| 191 | + SSEAlgorithm=If(use_cmk_arn, "aws:kms", "AES256"), |
| 192 | + KMSMasterKeyID=If( |
| 193 | + use_cmk_arn, Ref(cmk_arn), Ref("AWS::NoValue") |
| 194 | + ), |
| 195 | + ) |
| 196 | + ) |
| 197 | + ] |
| 198 | + ), |
| 199 | + NoValue, |
| 200 | + ), |
| 201 | + **common_bucket_conf, |
| 202 | +) |
| 203 | +template.add_resource(sftp_assets_bucket) |
| 204 | + |
| 205 | +# Output SFTP asset bucket name |
| 206 | +template.add_output( |
| 207 | + Output( |
| 208 | + "SFTPBucketDomainName", |
| 209 | + Condition=use_sftp_condition, |
| 210 | + Description="SFTP bucket domain name", |
| 211 | + Value=GetAtt(sftp_assets_bucket, "DomainName"), |
| 212 | + ) |
| 213 | +) |
| 214 | + |
| 215 | +assets_management_policy_statements = [ |
| 216 | + dict( |
| 217 | + Effect="Allow", |
| 218 | + Action=["s3:ListBucket"], |
| 219 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(assets_bucket)]), |
| 220 | + ), |
| 221 | + dict( |
| 222 | + Effect="Allow", |
| 223 | + Action=["s3:*"], |
| 224 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(assets_bucket), "/*"]), |
| 225 | + ), |
| 226 | + dict( |
| 227 | + Effect="Allow", |
| 228 | + Action=["s3:ListBucket"], |
| 229 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(private_assets_bucket)]), |
| 230 | + ), |
| 231 | + dict( |
| 232 | + Effect="Allow", |
| 233 | + Action=["s3:*"], |
| 234 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(private_assets_bucket), "/*"]), |
| 235 | + ), |
| 236 | +] |
168 | 237 |
|
| 238 | +assets_management_policy_statements_including_sftp_bucket = ( |
| 239 | + assets_management_policy_statements |
| 240 | + + [ |
| 241 | + dict( |
| 242 | + Effect="Allow", |
| 243 | + Action=["s3:ListBucket"], |
| 244 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(sftp_assets_bucket)]), |
| 245 | + ), |
| 246 | + dict( |
| 247 | + Effect="Allow", |
| 248 | + Action=["s3:*"], |
| 249 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(sftp_assets_bucket), "/*"]), |
| 250 | + ), |
| 251 | + ] |
| 252 | +) |
169 | 253 |
|
170 | 254 | # central asset management policy for use in instance roles
|
171 | 255 | assets_management_policy = iam.Policy(
|
172 | 256 | PolicyName="AssetsManagementPolicy",
|
173 | 257 | PolicyDocument=dict(
|
174 |
| - Statement=[ |
175 |
| - dict( |
176 |
| - Effect="Allow", |
177 |
| - Action=["s3:ListBucket"], |
178 |
| - Resource=Join("", [arn_prefix, ":s3:::", Ref(assets_bucket)]), |
179 |
| - ), |
180 |
| - dict( |
181 |
| - Effect="Allow", |
182 |
| - Action=["s3:*"], |
183 |
| - Resource=Join("", [arn_prefix, ":s3:::", Ref(assets_bucket), "/*"]), |
184 |
| - ), |
185 |
| - dict( |
186 |
| - Effect="Allow", |
187 |
| - Action=["s3:ListBucket"], |
188 |
| - Resource=Join("", [arn_prefix, ":s3:::", Ref(private_assets_bucket)]), |
189 |
| - ), |
190 |
| - dict( |
191 |
| - Effect="Allow", |
192 |
| - Action=["s3:*"], |
193 |
| - Resource=Join("", [arn_prefix, ":s3:::", Ref(private_assets_bucket), "/*"]), |
194 |
| - ), |
195 |
| - ], |
| 258 | + Statement=If( |
| 259 | + Condition(use_sftp_condition), |
| 260 | + assets_management_policy_statements_including_sftp_bucket, |
| 261 | + assets_management_policy_statements, |
| 262 | + ) |
196 | 263 | ),
|
197 | 264 | )
|
198 | 265 |
|
|
314 | 381 | )
|
315 | 382 |
|
316 | 383 | # Output CloudFront url
|
317 |
| - template.add_output(Output( |
318 |
| - "AssetsDistributionDomainName", |
319 |
| - Description="The assets CDN domain name", |
320 |
| - Value=GetAtt(distribution, "DomainName"), |
321 |
| - Condition=assets_use_cloudfront_condition, |
322 |
| - )) |
| 384 | + template.add_output( |
| 385 | + Output( |
| 386 | + "AssetsDistributionDomainName", |
| 387 | + Description="The assets CDN domain name", |
| 388 | + Value=GetAtt(distribution, "DomainName"), |
| 389 | + Condition=assets_use_cloudfront_condition, |
| 390 | + ) |
| 391 | + ) |
323 | 392 | else:
|
324 | 393 | distribution = None
|
| 394 | + |
| 395 | +# The scopedown policy is used to restrict a user's access to the parts of the bucket |
| 396 | +# we don't want them to access. |
| 397 | +common_sftp_scopedown_policy_statements = [ |
| 398 | + { |
| 399 | + "Sid": "AllowListingOfSFTPUserFolder", |
| 400 | + "Action": ["s3:ListBucket"], |
| 401 | + "Effect": "Allow", |
| 402 | + "Resource": ["arn:aws:s3:::${transfer:HomeBucket}"], |
| 403 | + "Condition": { |
| 404 | + "StringLike": { |
| 405 | + "s3:prefix": ["${transfer:UserName}/*", "${transfer:UserName}"] |
| 406 | + } |
| 407 | + }, |
| 408 | + }, |
| 409 | + { |
| 410 | + "Sid": "HomeDirObjectAccess", |
| 411 | + "Effect": "Allow", |
| 412 | + "Action": [ |
| 413 | + "s3:PutObject", |
| 414 | + "s3:GetObject", |
| 415 | + "s3:DeleteObjectVersion", |
| 416 | + "s3:DeleteObject", |
| 417 | + "s3:GetObjectVersion", |
| 418 | + ], |
| 419 | + "Resource": [ |
| 420 | + Join("/", [GetAtt(sftp_assets_bucket, "Arn"), "${transfer:UserName}"]), |
| 421 | + Join("/", [GetAtt(sftp_assets_bucket, "Arn"), "${transfer:UserName}/*"]), |
| 422 | + ], |
| 423 | + }, |
| 424 | +] |
| 425 | + |
| 426 | +sftp_kms_policy_statement = dict( |
| 427 | + Effect="Allow", |
| 428 | + Action=["kms:DescribeKey", "kms:GenerateDataKey", "kms:Encrypt", "kms:Decrypt"], |
| 429 | + Resource=Ref(cmk_arn), |
| 430 | +) |
| 431 | + |
| 432 | +sftp_scopedown_policy = iam.ManagedPolicy( |
| 433 | + # This is for applying when adding users to the transfer server. It's not used directly in the stack creation, |
| 434 | + # other than adding it to IAM for later use. |
| 435 | + "SFTPUserScopeDownPolicy", |
| 436 | + PolicyDocument=dict( |
| 437 | + Version="2012-10-17", |
| 438 | + Statement=If( |
| 439 | + use_sftp_with_kms_condition, |
| 440 | + common_sftp_scopedown_policy_statements + [sftp_kms_policy_statement], |
| 441 | + common_sftp_scopedown_policy_statements, |
| 442 | + ), |
| 443 | + ), |
| 444 | +) |
| 445 | +template.add_resource(sftp_scopedown_policy) |
| 446 | + |
| 447 | +# The ROLE is applied to users to let them access the bucket in general, |
| 448 | +# without regart to who they are. |
| 449 | +common_sftp_user_role_statements = [ |
| 450 | + dict( |
| 451 | + Effect="Allow", |
| 452 | + Action=["s3:ListBucket", "s3:GetBucketLocation"], |
| 453 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(sftp_assets_bucket)]), |
| 454 | + ), |
| 455 | + dict( |
| 456 | + Effect="Allow", |
| 457 | + Action=[ |
| 458 | + "s3:PutObject", |
| 459 | + "s3:GetObject", |
| 460 | + "s3:DeleteObject", |
| 461 | + "s3:DeleteObjectVersion", |
| 462 | + "s3:GetObjectVersion", |
| 463 | + "s3:GetObjectACL", |
| 464 | + "s3:PutObjectACL", |
| 465 | + ], |
| 466 | + Resource=Join("", [arn_prefix, ":s3:::", Ref(sftp_assets_bucket), "/*"]), |
| 467 | + ), |
| 468 | +] |
| 469 | + |
| 470 | +sftp_user_role = iam.Role( |
| 471 | + # This also is not used directly during the stack setup, but is put into IAM |
| 472 | + # to be used later when adding users to the transfer server. |
| 473 | + "SFTPUserRole", |
| 474 | + template=template, |
| 475 | + AssumeRolePolicyDocument=dict( |
| 476 | + Statement=[ |
| 477 | + dict( |
| 478 | + Effect="Allow", |
| 479 | + Principal=dict(Service=["transfer.amazonaws.com"]), |
| 480 | + Action=["sts:AssumeRole"], |
| 481 | + ) |
| 482 | + ] |
| 483 | + ), |
| 484 | + Policies=[ |
| 485 | + iam.Policy( |
| 486 | + "SFTPSUserRolePolicy", |
| 487 | + PolicyName="SFTPSUserRolePolicy", |
| 488 | + PolicyDocument=dict( |
| 489 | + Version="2012-10-17", |
| 490 | + Statement=If( |
| 491 | + use_sftp_with_kms_condition, |
| 492 | + common_sftp_user_role_statements + [sftp_kms_policy_statement], |
| 493 | + common_sftp_user_role_statements, |
| 494 | + ), |
| 495 | + ), |
| 496 | + ) |
| 497 | + ], |
| 498 | + RoleName=Join("-", [Ref("AWS::StackName"), "SFTPUserRole"]), |
| 499 | +) |
0 commit comments