Skip to main content

Dataset Permissions

Cognito based Dataset Permissions​

It is possible to restrict access to Datasets for CRUD operations using configuration direct on a depot-cdk Dataset resource. The following operations can be configured with your desired access levels:

  • create
  • read
  • update
  • delete

Access level configurations:

  • anonymous

  • authenticated

  • callerWithClaim

  • withExpression

  • callerWithCognitoGroup

  • none

  • Dataset access that does not meet the configured permission requirements via any of the Depot APIs will receive a PermissionDenied exception with HTTP status code 403.

  • Dataset permissions are used as a fallback if specific Schema(s) do not have explicit permissions defined.

  • When no explicit permissions have been defined (at any object level), the default access allows authenticated users to access resources. i.e. allowed = !anonymous. Taking this further, anonymous users are also able to view schemas (e.g. via GraphQL) but will not be able to execute those GQL queries.

note

The permissions across multiple resource levels are not merged: i.e. each Schema / Dataset / Environment permission set must be fully self-contained.

Requirements​

The requirements to use Dataset Permissions that integrate with Cognito are:

  • A Depot Cognito Location exists in the target environment.
  • A User schema named User exists for the target Dataset.
  • Auth is linked from the Cognito Location to the Dataset using the auth.cognito property.

Here is a sample in CDK for the Cognito Location and Dataset:

const cognitoRole = new Role(this, 'CognitoRole', {
assumedBy: new AccountPrincipal(depotEnvironment.accountId),
inlinePolicies: {
cognito: new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['cognito-idp:*'],
resources: ["arn:aws:cognito-idp:eu-west-1:1234566789012:userpool/eu-west-1_ZzzzzZZ"]
})
]
})
}
});

const cognito = new Location.Cognito(this, "CognitoLocation", {
environment: depotEnvironment,
name: "cognito",
roleArn: cognitoRole.roleArn,
userPoolId: "eu-west-1_ZzzzzZZ",
clientId: "abc123456"
});

new Dataset(this, "Dataset", {
// etc...
auth: {
cognito: cognito.cognitoAuth
},
permissions: {
create: Permissions.authenticated(),
read: Permission.anonymous(),
// etc...
}
});

How to use Dataset Permissions​

Use the depot-cdk Permission resource to access the functions to set access levels for each CRUD operation on your target Dataset.

For example, to allow anonymous access for read operations on a target dataset, you would set the following configuration:

new Dataset(stack, "DatasetWithAnonymousReadPermission", {
permissions: {
read: Permission.anonymous()
}
});

To only allow authenticated access, you would use the Permission.authenticated() function for the desired CRUD operation(s).

Cognito groups​

The Permission.callerWithCognitoGroup() function is used to configure target CRUD operation access for a specific Cognito User Group. For example:

new Dataset(stack, "DatasetWithCongitoGroups", {
permissions: {
read: Permission.callerWithCognitoGroup("kennel_auditor"),
create: Permission.callerWithCognitoGroup("kennel_admin")
}
});

Custom permissions with expressions​

You can fully customise permission configurations for CRUD operations on a target dataset by using the Permission.withExpression() function.

For example:

new Dataset(stack, "DatasetWithPermissionExpression", {
permissions: {
read: Permission.withExpression("'kennel_auditor' in caller.claims['cognito:group']"),
delete: Permission.withExpression("'kennel_admin' in caller.claims['cognito:group']"),
create: Permission.withExpression("'kennel_custodian' in caller.claims['cognito:group']")
}
});

No user access permissions​

To prevent user access (anonymous or authenticated) - i.e. no user access at all, use the Permission.none() function.

No access will be allowed via any of the Depot APIs for the operations specified, aside from access via the Depot Lambda Gateway (which acts as a kind of superuser internally only).

For example:

new Dataset(stack, "DatasetWithNoUserAccess", {
permissions: {
read: Permission.none(),
delete: Permission.none(),
create: Permission.none(),
update: Permission.none()
}
});

Environment permissions​

It is possible to configure default permissions on a Depot environment in the same style as on Datasets:

this.depotEnvironment = new depot.Environment(this, "DepotEnvironment", {
// etc...
permissions: {
create: Permissions.authenticated(),
read: Permission.anonymous(),
update: Permission.none(),
// etc...
}
});

Environment permissions are used only if Schema and Dataset have no permissions defined. The permissions are not merged: i.e. each Schema/Dataset/Environment permissions must be fully self-contained.

IAM Dataset Permissions​

The DatasetPrincipalPermission depot-cdk resource provides:

  • A custom resource that adds or removes AWS IAM principal permission grants to facilitate access to a dataset configured with IAM authentication (via the Dataset resource property auth.iam).

IAM principals can be added directly on Dataset definitions in CDK (on the Dataset auth.iam.principals), however in cases where you might want to add principals to a 'remote' stack Dataset, you can use this resource, using the environment ID and dataset ID.

Example usage​

Example:

new DatasetPrincipalPermission(stack, "MyDatasetPermission", {
environmentId: "environment123",
datasetId: "dataset123",
principal: "arn:aws:iam::123456789012:role/MyRoleName"
});

The IAM principal for a Dataset Principal Permission construct will be added and merged together with the target dataset's existing IAM principals.

Asking for direct Iceberg access​

By default the construct grants access through Depot's IAM gateway. purposes selects the planes instead, and one of them is direct access to the dataset's S3 Tables Iceberg files, bypassing Depot — the same grant directReadPrincipals makes on the dataset itself, declared from the consumer's own stack:

new DatasetPrincipalPermission(stack, "SparkDirectRead", {
environmentId: "environment123",
datasetId: "dataset123",
principal: sparkRole.roleArn,
purposes: { s3tablesRead: true },
// Attaches `lakeformation:GetDataAccess`, which the Glue Iceberg REST route needs on the caller's own
// identity policy and Depot cannot add to a role in your stack.
grantee: sparkRole,
});

s3tablesWrite implies s3tablesRead. Depot's next deploy provisions the grants; see Iceberg interop for what each route can do.

Listing any purpose is exhaustive — what you do not list is not granted. Asking for s3tablesRead alone therefore drops gateway-API access; pass { gatewayApi: true, s3tablesRead: true } for both. Omitting purposes entirely means { gatewayApi: true }, so permissions written before the field existed are unaffected.

Either S3 Tables purpose requires principal to be a role ARN. Neither Lake Formation nor an S3 Tables resource policy accepts a session as a principal, so an assumed-role ARN — what aws sts get-caller-identity reports — is refused at synth. The gateway plane still accepts a user or account ARN.