1616
1717POLICY_NAME_FORMAT = "{bucket_name}-owner-policy"
1818
19- REQUIRE_HTTPS_CONDITION = {
20- "Bool" : {
21- # Require HTTPS
22- "aws:SecureTransport" : "true"
23- },
24- "NumericGreaterThanEquals" : {
25- # Require TLS >= 1.2
26- "s3:TlsVersion" : ["1.2" ]
27- },
28- }
29-
3019
3120class BucketCreator :
3221 def __init__ (self , profile_name = None , region_name = None ):
@@ -77,11 +66,36 @@ def format_path(path):
7766 "Principal" : "*" ,
7867 "Action" : ["s3:GetObject" ],
7968 "Resource" : paths_resources ,
80- # Require HTTPS for public requests
81- "Condition" : REQUIRE_HTTPS_CONDITION ,
8269 }
8370
8471 def get_bucket_policy_statements_for_user_access (self , bucket , user ):
72+ # Deny access using a version of TLS older than 1.2.
73+ # This is also enforced by S3, but included here for visibility.
74+ yield {
75+ "Sid" : "DenyOutdatedTLS" ,
76+ "Effect" : "Deny" ,
77+ "Principal" : "*" ,
78+ "Action" : "s3:*" ,
79+ "Resource" : [
80+ f"arn:aws:s3:::{ bucket .name } " ,
81+ f"arn:aws:s3:::{ bucket .name } /*" ,
82+ ],
83+ "Condition" : {"NumericLessThan" : {"s3:TlsVersion" : "1.2" }},
84+ }
85+
86+ # Deny access which isn't over HTTPS
87+ yield {
88+ "Sid" : "DenyInsecureTransport" ,
89+ "Effect" : "Deny" ,
90+ "Principal" : "*" ,
91+ "Action" : "s3:*" ,
92+ "Resource" : [
93+ f"arn:aws:s3:::{ bucket .name } " ,
94+ f"arn:aws:s3:::{ bucket .name } /*" ,
95+ ],
96+ "Condition" : {"Bool" : {"aws:SecureTransport" : "false" }},
97+ }
98+
8599 # Create policy statement giving the created user access to
86100 # non-destructive actions on the bucket.
87101 yield {
@@ -95,8 +109,6 @@ def get_bucket_policy_statements_for_user_access(self, bucket, user):
95109 "s3:ListBucketVersions" ,
96110 ],
97111 "Resource" : "arn:aws:s3:::{bucket_name}" .format (bucket_name = bucket .name ),
98- # Require HTTPS for API
99- "Condition" : REQUIRE_HTTPS_CONDITION ,
100112 }
101113 # Create policy statement giving the created user full access over the
102114 # objects.
@@ -106,14 +118,11 @@ def get_bucket_policy_statements_for_user_access(self, bucket, user):
106118 "Principal" : {"AWS" : user .arn },
107119 "Action" : "s3:*" ,
108120 "Resource" : "arn:aws:s3:::{bucket_name}/*" .format (bucket_name = bucket .name ),
109- # Require HTTPS for API
110- "Condition" : REQUIRE_HTTPS_CONDITION ,
111121 }
112122
113123 def set_bucket_policy (
114124 self , bucket , user , allow_public_acls , public_get_object_paths = None
115125 ):
116- policy_statement = []
117126 public_access = bool (public_get_object_paths )
118127
119128 # NB: This API doesn't exist on a `Bucket`
@@ -129,15 +138,16 @@ def set_bucket_policy(
129138 if public_access or allow_public_acls :
130139 print ("Configured public access to bucket." )
131140
141+ policy_statement = list (
142+ self .get_bucket_policy_statements_for_user_access (bucket , user )
143+ )
144+
132145 if public_access :
133146 policy_statement .append (
134147 self .get_bucket_policy_statement_for_get_object (
135148 bucket , public_get_object_paths
136149 )
137150 )
138- policy_statement .extend (
139- list (self .get_bucket_policy_statements_for_user_access (bucket , user ))
140- )
141151 policy = json .dumps (
142152 {
143153 "Version" : "2012-10-17" ,
@@ -148,7 +158,7 @@ def set_bucket_policy(
148158 try :
149159 bucket .Policy ().put (Policy = policy )
150160 except ClientError as e :
151- if e .response ["Error" ]["Code " ] == "MalformedPolicy " :
161+ if e .response ["Error" ]["Message " ] == "Invalid principal in policy " :
152162 print (
153163 "Waiting for the user to be available to be "
154164 "attached to the policy (wait 5s)."
0 commit comments