The condition key aws:SourceIp checks the IP address of the principal making the request. When using an IAM role, the source IP is that of the role's session, not the end user. If the role is assumed from outside the corporate network, the source IP will be the external IP of the client machine, not the corporate range.
The condition should use aws:SourceIdentity or similar? Actually, aws:SourceIp works for the client IP of the request. But if the role is assumed by a user outside the network, the request comes from that user's IP. However, the condition should work.
Wait: The issue might be that the policy allows the role, but the role itself might have permissions that override? Or the condition is incorrectly applied? The most likely cause is that the condition key aws:SourceIp does not work when the request is made via AWS CLI or SDK from outside? Actually, it should. Another common issue: The condition aws:SourceIp is evaluated against the IP address of the principal, but if the role is assumed by an EC2 instance, the source IP is the instance's private IP? No, that's for VPC endpoints. Hmm.
Let's think about typical exam: The condition aws:SourceIp does not work for requests that come from within a VPC because the source IP is the private IP? Actually, if the role is assumed by an EC2 instance inside the VPC, the source IP is the instance's private IP, which might be within 10.0.0.0/16. But if the role is assumed by a user outside the network, the source IP is the user's public IP, which might not be in 10.0.0.0/16. So the condition should block.
But the question says users can still upload from outside. Possible cause: The condition key is misspelled? No. Another possibility: The policy allows the role, but the role has its own policy that allows s3:PutObject without the condition.
Actually, the bucket policy grants the role permission conditionally, but if the role itself has an IAM policy that grants the same action without the condition, the user might be able to upload using the role's permissions? No, both policies must be satisfied? Actually, if the role has an IAM policy that allows s3:PutObject without conditions, the user assuming the role could upload from anywhere because the role's policy is effective. The bucket policy adds additional restrictions but does not override the role's IAM policy. Wait, that's not correct: For access to S3, if the principal has IAM permissions, the bucket policy can further restrict or allow.
But if the IAM policy allows the action, the bucket policy can deny it. However, if the bucket policy allows conditionally, and the IAM policy allows unconditionally, the effective permission is allow because the bucket policy does not deny. Actually, the evaluation logic: by default, all requests are denied.
An explicit allow in either IAM or bucket policy is not enough; both must allow? No, the AWS access control policy evaluation: An explicit allow in either IAM or bucket policy will allow access, unless there is an explicit deny. So if the IAM role has an explicit allow for s3:PutObject without condition, and the bucket policy has an explicit allow with condition, the request is allowed if the condition is met, but if the condition is not met, the bucket policy does not grant allow, but the IAM policy still grants allow? Actually, the bucket policy is a resource-based policy; if it does not grant access (because condition fails), it is not an explicit allow, but it is not an explicit deny either. The IAM policy explicitly allows the action.
The net effect is that the request is allowed because there is an explicit allow from the IAM policy and no explicit deny from the bucket policy. Wait, but the bucket policy has an allow statement with a condition; if the condition is not met, the statement does not apply, so it's as if the bucket policy does not have that statement. So the IAM policy's allow stands.
Therefore, the bucket policy condition is ineffective if the IAM policy already allows the action. To enforce the condition, the bucket policy must include a Deny statement for requests not meeting the condition. That is a common gotcha.
So the correct answer is that the bucket policy should use a Deny effect, not Allow. Or the IAM policy should be more restrictive. So the most likely cause: The bucket policy uses Allow instead of Deny.