Skip to content

[BUG] SMUS User Role Cannot Read Glue Job Scripts from Project Bucket #54

Description

@marcinc

This is issue is related to #52

Summary

When a user clicks Script on a Glue job in the SageMaker Unified Studio (SMUS) Data Processing Jobs view, the script content fails to load with an s3:GetObject explicit-deny error. The project S3 bucket's catch-all deny policy fires against the SMUS user role (datazone_usr_role_<projectId>_<userId>) because that role is not in any allow list and is not excluded from the deny.

Affected version

@aws-mdaa/dataops-project v1.5.0

Component

packages/constructs/L3/dataops/dataops-project-l3-construct/lib/dataops-project-l3-construct.ts
createProjectBucket — bucket policy construction

Error message

Error loading script: User: arn:aws:sts::<account>:assumed-role/datazone_usr_role_<projectId>_<userId>/<sessionId>
is not authorized to perform: s3:GetObject on resource:
"arn:aws:s3:::test123-dev-dataops-project123/deployment/jobs/counts/counts.py"
with an explicit deny in a resource-based policy

Root cause

dataops-project creates two distinct DataZone-related IAM roles:

Role Created by Purpose
<prefix>-dz-user MDAA (createDatazoneUserRole) DataZone environment operations; assumable by datazone.amazonaws.com
datazone_usr_role_<projectId>_<userId> SMUS dynamically at session time Individual user Studio sessions in SMUS

The MDAA-created dz-user role is excluded from the bucket's catch-all deny policy and is allowed on /athena-results. The SMUS user role, however, is created by AWS at the moment a user opens the SMUS Studio -- it is not known to MDAA at deploy time and therefore appears nowhere in the bucket policy.

The project bucket's deny statement uses a ForAnyValue:StringNotLike condition on aws:userId (role IDs) and aws:PrincipalArn (exact ARNs). Because datazone_usr_role_* is in neither list, the catch-all deny fires:

Effect: Deny
Action: [s3:PutObject*, s3:GetObject*, s3:DeleteObject*]
Condition:
  ForAnyValue:StringNotLike:
    aws:userId: [AROAXX:*, AROAYY:*, ...]     ← execution roles, admin roles, dz-user
    aws:PrincipalArn: [arn:.../deployment-role]

The explicit deny overrides any allow elsewhere. No separate allow for the /deployment prefix was present either -- that prefix was only open to execution roles (Glue runners) and the CDK deployer.

AWS SMUS creates roles following the pattern datazone_usr_role_<projectId>_<userId> for all users who access the Studio. This is a well-documented AWS naming convention, account-scoped, and safe to use in IAM wildcard patterns within the same account.

Proposed Fix

Two additions inside createProjectBucket:

1. Allow s3:GetObject* on deployment/* for SMUS user roles

const smusUserRoleArnPattern = `arn:aws:iam::${this.account}:role/datazone_usr_role_*`;
const smusUserRoleDeploymentRead = new PolicyStatement({
  sid: 'SmusUserRoleDeploymentRead',
  effect: Effect.ALLOW,
  actions: RestrictObjectPrefixToRoles.READ_ACTIONS,
  resources: [projectBucket.arnForObjects('deployment/*')],
  conditions: { StringLike: { 'aws:PrincipalArn': smusUserRoleArnPattern } },
});
smusUserRoleDeploymentRead.addAnyPrincipal();
projectBucket.addToResourcePolicy(smusUserRoleDeploymentRead);

2. Exempt SMUS user roles from the catch-all deny

const bucketRestrictPolicy = new RestrictBucketToRoles({
  ...
  principalExcludes: [
    projectDeploymentRole.roleArn,
    smusUserRoleArnPattern,   // <-- new
  ],
});

This adds arn:aws:iam::<account>:role/datazone_usr_role_* to the aws:PrincipalArn values in the ForAnyValue:StringNotLike deny condition. When the SMUS user role's ARN matches the pattern, the deny does not fire, and the explicit allow on deployment/* takes effect.

Scope of the wildcard:

arn:aws:iam::<account>:role/datazone_usr_role_* is:

  • Scoped to the same AWS account so no cross-account exposure
  • Limited to AWS SMUS-generated user roles by naming convention
  • Read-only on deployment/* (Glue scripts); no write, no data/*, no temp/*
  • Consistent with how the existing dz-user role is treated (excluded from deny, allowed on /athena-results)

Impact

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions