AWS sagemaker: Restrict cross-account S3 access for model packages
Summary
Expands the guide on scoping cross-account S3 access to model artifacts via the sagemaker:ModelPackageArn session tag. Adds a new AllowModelPackageRegistrationReads bucket-policy statement (scoped to a registration role and aws:PrincipalOrgID), clarifies that the tag applies for the endpoint's lifetime and to inference-container credentials, notes serverless/inference-component limitations, requires kms:Decrypt in both key policy and IAM policy, and adds warnings about over-broad ARN wildcards plus CloudTrail/S3-log verification caveats.
Security assessment
The change is security documentation for least-privilege, cross-account access to model artifacts: it adds a narrowly scoped bucket-policy statement (single registration role, aws:PrincipalOrgID condition), explains that the sagemaker:ModelPackageArn session tag gates reads to endpoint sessions, requires kms:Decrypt in both the key policy and the role's IAM policy, and warns that an over-broad ARN wildcard (e.g. version '1*' matching 10/11/19) silently grants access to unintended versions. It documents authorization hardening rather than fixing a specific vulnerability or incident, so no CVE or concrete exploit is referenced.
Evidence
+`AllowModelPackageRegistrationReads` is required. `CreateModelPackage` reads the artifact to validate it, and at that point the model package does not exist yet, so no `sagemaker:ModelPackageArn` session tag can be present. Without this statement, the first statement denies registration, and you cannot create the model package at all. Set `model-registration-role` to the role that calls `CreateModelPackage`, and keep it scoped to that role rather than to the whole account.
Diff
diff --git a/sagemaker/latest/dg/model-registry-restrict-s3-access.md b/sagemaker/latest/dg/model-registry-restrict-s3-access.md index 250375d..70f0c44 100644 --- a//sagemaker/latest/dg/model-registry-restrict-s3-access.md +++ b//sagemaker/latest/dg/model-registry-restrict-s3-access.md @@ -11 +11 @@ Step 1: Tag and scope the execution roleStep 2: Add a service control policyStep -When you share a model package across accounts, the consuming account's execution role needs `s3:GetObject` on the model artifacts in the producing account. By default, that permission applies whenever the role is used. As a result, any principal that uses the role can read the artifacts from a notebook, from a training job, or through a direct API call—not only while a model package is being deployed. +When you share a model package across accounts, the consuming account's execution role needs `s3:GetObject` on the model artifacts in the producing account. By default, that permission applies whenever the role is used. As a result, any principal that uses the role can read the artifacts from a notebook, from a training job, or through a direct API call—not only from an endpoint deployed from a model package. @@ -13 +13,7 @@ When you share a model package across accounts, the consuming account's executio -You can narrow that access so that only a model package deployment can read the artifacts. During deployment, SageMaker AI applies the session tag `sagemaker:ModelPackageArn` to the execution-role session it assumes. The tag value is the ARN of the model package being deployed. A bucket policy that requires this tag therefore grants access only to deployment sessions. +You can narrow that access so that only endpoints deployed from a model package can read the artifacts. When you deploy an endpoint from a model package, SageMaker AI applies the session tag `sagemaker:ModelPackageArn` to the execution-role sessions it assumes for that endpoint. The tag value is the ARN of the model package version. The tag applies for the life of the endpoint, both to the sessions SageMaker AI uses to download the model artifacts and to the credentials that the inference container receives at runtime. A bucket policy that requires this tag therefore grants access only to sessions that belong to an endpoint deployed from a matching model package. Notebooks, training jobs, and endpoints deployed from a plain container image do not carry the tag. + +If code in your inference container assumes another role, the resulting credentials do not carry the `sagemaker:ModelPackageArn` tag. + +###### Note + +This applies to real-time endpoint deployments. Serverless endpoints and inference components do not carry the `sagemaker:ModelPackageArn` session tag, so a bucket policy that requires the tag denies them at read time. If you need to deploy the same artifacts that way, keep them in a bucket that does not require the tag. @@ -85 +91 @@ Both statements use `StringNotEquals` on `aws:PrincipalServiceName`, which evalu -In the producing account, apply the following policy to the bucket holding the model artifacts. All three conditions must hold. Amazon S3 denies any session that is missing one. +In the producing account, apply the following policy to the bucket holding the model artifacts. The first statement governs reads by endpoints deployed from a model package. All three of its conditions must hold, and Amazon S3 denies any session that is missing one. The second statement allows model package registration, which happens before any deployment tag exists. @@ -106,0 +113,17 @@ In the producing account, apply the following policy to the bucket holding the m + }, + { + "Sid": "AllowModelPackageRegistrationReads", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::registering-account-id:role/model-registration-role" + }, + "Action": [ "s3:GetObject", "s3:ListBucket" ], + "Resource": [ + "arn:aws:s3:::model-artifacts-bucket", + "arn:aws:s3:::model-artifacts-bucket/model-package-prefix/*" + ], + "Condition": { + "StringEquals": { + "aws:PrincipalOrgID": "o-organization-id" + } + } @@ -111 +134,11 @@ In the producing account, apply the following policy to the bucket holding the m -Using `Principal` with a value of `*` together with these conditions means any role in your organization that is tagged `ManagedBy=SageMaker` and carries the deployment tag can read the artifacts. You do not have to edit the policy for each consuming role. The wildcard on the model package ARN covers every version in the group. +`AllowModelPackageRegistrationReads` is required. `CreateModelPackage` reads the artifact to validate it, and at that point the model package does not exist yet, so no `sagemaker:ModelPackageArn` session tag can be present. Without this statement, the first statement denies registration, and you cannot create the model package at all. Set `model-registration-role` to the role that calls `CreateModelPackage`, and keep it scoped to that role rather than to the whole account. + +Using `Principal` with a value of `*` together with these conditions means any role in your organization can read the artifacts, provided it is tagged `ManagedBy=SageMaker` and carries the session tag. You do not have to edit the policy for each consuming role. The wildcard on the model package ARN covers every version in the group. + +To allow more than one model package group, add one statement per group. Pair that group's ARN pattern with that group's artifact prefix. The condition also accepts a list of ARN patterns in a single statement. Use that form only when the groups are meant to share the same artifacts, because a single statement grants every pattern it lists access to everything its `Resource` covers. + +Artifacts from more than one producer account need the same treatment: one pattern per account, because the tag value carries the account that owns the model package. + +###### Important + +Do not put a wildcard immediately after a version number. A pattern ending `model-package/`model-package-group`/1*` also matches versions 10, 11, and 19. To restrict access to a single version, end the pattern at the version and omit the wildcard. An over-broad pattern is not visible from the endpoint or the model package, because deployments succeed either way. @@ -115 +148 @@ Using `Principal` with a value of `*` together with these conditions means any r -Scope `Resource` to the artifacts of a single model package group. A prefix spanning several groups would let a deployment of one model package read another group's artifacts, because the session tag is checked against the group wildcard rather than the object path. +Scope `Resource` to the artifacts of a single model package group. A prefix spanning several groups would let a deployment of one model package read another group's artifacts. The session tag is checked against the group wildcard rather than the object path. @@ -117 +150 @@ Scope `Resource` to the artifacts of a single model package group. A prefix span -If the artifacts are encrypted with a customer managed AWS KMS key, the execution role also needs `kms:Decrypt` on that key. Grant it in the key policy; an IAM policy alone is not sufficient. +If the artifacts are encrypted with a customer managed AWS KMS key, the execution role also needs `kms:Decrypt` on that key. Because the key and the role are in different accounts, grant it in both places: the key policy in the producing account must allow the execution role, and the execution role's IAM policy must allow `kms:Decrypt` on the key. Either grant alone is not sufficient. @@ -123 +156 @@ Your account records both the tagging of the session and the resulting access de - * In CloudTrail, the `AssumeRole` event for the execution role lists the session tags under `requestParameters`. Confirm that `sagemaker:ModelPackageArn` is present and matches the model package you deployed. + * In CloudTrail, the `AssumeRole` event for the execution role lists the session tags under `requestParameters`. Confirm that at least one event carries `sagemaker:ModelPackageArn` and that its value matches the model package you deployed. A single deployment also produces _untagged_ `AssumeRole` events, because SageMaker AI validates the artifact before the tagged session is created. Untagged events alongside a tagged one are expected and do not mean the tag was not applied. @@ -125 +158 @@ Your account records both the tagging of the session and the resulting access de - * In Amazon S3 data events or server access logs, `GetObject` requests against the artifact prefix show whether each read was allowed or denied, so you can confirm that non-deployment access is being refused. + * In Amazon S3 data events or server access logs, `GetObject` requests against the artifact prefix show whether each read was allowed or denied, so you can confirm that access from outside a model package endpoint is being refused. A successful deployment also produces a denied `GetObject` from SageMaker AI, because SageMaker AI validates the artifact with an untagged session before the tagged session is created. This denial is expected and does not stop the deployment. @@ -130 +163 @@ Your account records both the tagging of the session and the resulting access de -Before applying the policies to a production bucket, you can evaluate them with the IAM policy simulator to confirm that a deployment session is allowed and that a session without the tag is denied. For more information, see [Testing IAM policies with the IAM policy simulator](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html). +Before applying the policies to a production bucket, you can evaluate them with the IAM policy simulator to confirm that a deployment session is allowed and that a session without the tag is denied. The simulator evaluates your policy against context keys that you supply, so it confirms the policy logic but not that a deployment actually produces the tag. Confirm that separately in CloudTrail, as described earlier in this section. For more information, see [Testing IAM policies with the IAM policy simulator](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html).