diff --git a/docs/buckets/soft-delete.mdx b/docs/buckets/soft-delete.mdx index 7628e2ef..29c5e4bd 100644 --- a/docs/buckets/soft-delete.mdx +++ b/docs/buckets/soft-delete.mdx @@ -9,11 +9,10 @@ keeps the deleted object for a configurable retention window during which you can list it, restore it, or permanently remove it. Once the retention window expires, Tigris cleans the data up automatically. -The same retention policy also protects the bucket itself: deleting a bucket -with soft delete enabled moves the bucket into a soft-deleted state instead of -hard deleting it. A soft-deleted bucket can be restored back into an active -bucket within the retention window, and is permanently removed once the -retention window expires. +Soft delete also protects the bucket itself: deleting a bucket with soft delete +enabled moves the bucket into a soft-deleted state instead of hard deleting it. +A soft-deleted bucket stays until you restore it or permanently delete it. +Tigris does not remove it when the retention window expires. ## How soft delete works @@ -27,24 +26,30 @@ When soft delete is enabled on a bucket: them, restore them to a live state, or permanently delete them ahead of the schedule. - Deleting a bucket with soft delete enabled moves the bucket itself into a - soft-deleted state. The bucket and its data stay recoverable for the retention - window. -- After the retention window passes, Tigris permanently removes the soft-deleted - data and reclaims its storage. + soft-deleted state. The bucket and its data stay recoverable until you restore + the bucket or permanently delete it. +- After the retention window passes, Tigris permanently removes soft-deleted + objects from active buckets and reclaims their storage. - Soft-deleted data continues to consume storage and is billed at the same rate as live data until it is removed. At a glance, the lifecycle looks like this: ``` - DELETE ──► soft-deleted state ──┬──► permanently removed -bucket or object (recoverable) │ (async, after retention) - │ - ◄─── restore ─────┘ + DELETE object ──► soft-deleted state ──┬──► permanently removed + (recoverable) │ (async, after retention) + │ + ◄─── restore ─────┘ + + DELETE bucket ──► soft-deleted state ──┬──► permanently removed + (recoverable) │ (only when you delete + │ it permanently) + ◄─── restore ─────┘ ``` -Cleanup runs asynchronously, so data is removed shortly after the retention -window passes. +Cleanup runs asynchronously, so objects are removed shortly after the retention +window passes. A soft-deleted bucket is not cleaned up automatically. It is +removed only when you permanently delete it. ## Enabling soft delete on a bucket @@ -67,9 +72,9 @@ delete enabled, showing **Enabled** or **Disabled** for each row. ### Retention window -The retention window controls how long deleted buckets and objects remain -recoverable. It must be between **7 and 90 days**, and defaults to **7 days** -when soft delete is first enabled. +The retention window controls how long deleted objects remain recoverable. It +does not apply to deleted buckets. It must be between **7 and 90 days**, and +defaults to **7 days** when soft delete is first enabled. ### Enabling soft delete programmatically @@ -179,8 +184,7 @@ delete and then deletes objects must wait before it relies on recovery. When you delete a bucket that has soft delete enabled, the delete confirmation dialog reflects that the action is recoverable instead of permanent. It tells -you the bucket can be restored within its retention period — and that after that -window passes, the deletion is permanent. The action button is labeled **Soft +you that you can restore the bucket. The action button is labeled **Soft Delete** rather than **Delete**, and you still confirm by typing the bucket name. @@ -193,12 +197,12 @@ below rather than being permanently removed. A bucket deleted while soft delete was enabled is not removed immediately. It moves to a soft-deleted state where it is hidden from your normal bucket list -but stays recoverable until the retention window expires. +but stays recoverable until you restore it or permanently delete it. In the Tigris Dashboard sidebar, **Buckets** expands into **All**, **Forks**, **Owned by me**, and **Deleted**. Every bucket that was deleted while soft delete was enabled appears under **Deleted**. Each row in this view is a -soft-deleted bucket that is still within its retention window. +soft-deleted bucket. To restore a bucket, open **Buckets → Deleted** in the sidebar. Then open the row's overflow menu (`...`) and choose **Restore**: @@ -207,9 +211,8 @@ row's overflow menu (`...`) and choose **Restore**: After a successful restore, the bucket is fully active again — it moves back to the regular bucket list and every object it held at the time of deletion is live -and readable, exactly as it was before the bucket was deleted. If you want to -remove a soft-deleted bucket immediately instead of waiting for the retention -window to expire, choose **Delete** from the same menu. +and readable, exactly as it was before the bucket was deleted. To remove a +soft-deleted bucket permanently, choose **Delete** from the same menu. While a bucket is in the soft-deleted state, its name stays reserved — you cannot create a new bucket with the same name until either the bucket is @@ -745,9 +748,15 @@ earlier versions live and accessible. ## Things to note -- Retention applies per bucket. Every soft-deleted bucket and object in the - bucket uses the same retention window. -- Disabling soft delete on a bucket does not purge data that is already - soft-deleted. It continues to age out on its original retention schedule. -- Changing the retention value affects new soft deletes from that point forward. - Already soft-deleted data keeps the retention it was created with. +- Retention applies per bucket. Every soft-deleted object in the bucket uses the + bucket's current retention window. +- Changing the retention value also applies to objects that are already + soft-deleted. A shorter window can remove them sooner. + +:::warning + +Do not turn off soft delete while you still need to restore deleted objects. +When soft delete is off, Tigris can remove the objects that are already +soft-deleted. You cannot restore them after that. + +::: diff --git a/docs/partner-integrations/access-control.mdx b/docs/partner-integrations/access-control.mdx index 57e9b88b..2516fdde 100644 --- a/docs/partner-integrations/access-control.mdx +++ b/docs/partner-integrations/access-control.mdx @@ -3,22 +3,24 @@ When you create access keys through the Partner API, three fields control what those keys can do: -- `user_role` controls what your user can do through the **management API** - (listing keys, updating org settings). +- `user_role` tells Tigris what the user in `user_id` can do in **this Partner + API call**: which access keys the call can manage, and which bucket roles it + can grant. - `buckets_roles` controls what **S3 operations** the access key can perform on specific buckets. - `access_key_scope` controls whether the key also receives [default allowed operations](/docs/iam/manage-access-key/#default-allowed-operations) such as create bucket and list buckets. -These fields are independent. They apply at different times and serve different -purposes. +`buckets_roles` and `access_key_scope` are stored on the access key and apply to +every request the key makes. `user_role` applies only to the call that you pass +it on. Tigris does not store it on the key. -| Field | Where it applies | What it controls | -| ------------------ | ------------------ | --------------------------------------------------------- | -| `user_role` | Partner API calls | Management scope: list all keys vs own keys, org settings | -| `buckets_roles` | S3 data operations | What the access key can read, write, or manage per bucket | -| `access_key_scope` | S3 and IAM APIs | Whether the key receives default allowed operations | +| Field | Where it applies | What it controls | +| ------------------ | -------------------- | ---------------------------------------------------------------- | +| `user_role` | One Partner API call | Which keys the call can manage and which bucket roles it can set | +| `buckets_roles` | S3 requests | What the access key can read, write, or manage per bucket | +| `access_key_scope` | S3 and IAM requests | Whether the key receives default allowed operations | import PartnerAccessControlDiagram from "@site/src/components/diagrams/PartnerAccessControlDiagram"; @@ -29,12 +31,12 @@ import PartnerAccessControlDiagram from "@site/src/components/diagrams/PartnerAc ## Organization Role (`user_role`) The `user_role` field tells Tigris what privileges this user has in your system. -You pass it on provisioning, access key, and org management endpoints. +You pass it on provisioning and access key calls. -| Value | What it means | -| -------- | ----------------------------------------------------------------------------------------- | -| `Admin` | Full org access. Can manage all access keys, update org settings, and view all resources. | -| `Member` | Standard access. Can only manage their own access keys and resources. | +| Value | What the call can do | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `Admin` | View, update, rotate, and delete any access key in the org. Grant any bucket role on any bucket in the org, including `"*"`. | +| `Member` | View, rotate, and delete only the access keys of `user_id`. Change the bucket roles and the scope of only those keys. Grant bucket roles only on buckets that `user_id` provisioned. | The behavioral difference shows up immediately. When you call [List Access Keys](/docs/partner-integrations/api/tigris-list-access-keys) with @@ -42,39 +44,46 @@ The behavioral difference shows up immediately. When you call `user_role: "Member"` (or omitted), you get back **only keys owned by that user**. -This same scoping applies to other management operations. Admin-only operations -include: +If you omit `user_role`, the call is treated as `Member`. A `Member` call that +grants a role on a bucket that `user_id` did not provision fails with a +permission error. If your backend manages access for all of your users, pass +`user_role: "Admin"`. -- **Manage all access keys** -- view, rotate, or delete any key in the org, not - just the user's own -- **Update org settings** -- change org name, quotas, active status -- **Invite and manage users** -- send invitations, update roles, remove members +`user_role` does not limit IAM policies. A `Member` call can create a policy for +any bucket in the org. It can also attach a policy to, or detach a policy from, +any access key in the org. -If you omit `user_role`, the user is treated as a `Member`. For most -integrations, `Member` is the right default. +The access key that the call creates does not become an admin. Its access comes +only from its `buckets_roles`, its `access_key_scope`, and its IAM policies. ## Bucket Roles (`buckets_roles`) The `buckets_roles` field is an array of `{bucket_name, role}` pairs stored on -the access key. Four roles are available: `ReadOnly`, `ReadWrite`, `Editor`, and -`Admin`. See the +the access key. See the [RBAC permissions table](/docs/concepts/authnz#role-based-access-control-rbac) for exactly which S3 operations each role permits. -Use `ReadWrite` for object reads and writes without bucket administration. Use -`Editor` when the key must also manage bucket configuration, public access, or -bucket deletion. Editors cannot manage bucket shares or IAM policies. +| Role | What the key can do on the bucket | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `ReadOnly` | Read and list objects. Create snapshots and forks. | +| `ReadWrite` | Everything in `ReadOnly`, plus write and delete objects. It cannot change bucket settings or delete the bucket. | +| `Editor` | Everything in `ReadWrite`, plus bucket settings, public access, and bucket deletion. It cannot manage bucket shares or IAM policies. | +| `Admin` | Every operation on every bucket in the org. Use it only with `"bucket_name": "*"`. | -Use `"*"` as the bucket name to grant access to all buckets in the org. An -access key with `{"bucket_name": "*", "role": "Admin"}` is treated as a full org -admin, bypassing all bucket-level permission checks. +Use `"*"` as the bucket name to give a role on all buckets in the org, including +buckets created later. A key can have only one `"*"` entry, and only a +`user_role: "Admin"` call can grant it. -## Access key scope (`access_key_scope`) {#access-key-scope} +`{"bucket_name": "*", "role": "Admin"}` must be the only entry on the key. That +key is a full org admin. It can do every operation on every bucket, except the +deletes that [delete protection](#how-tigris-evaluates-a-request) blocks. + +## Access Key Scope (`access_key_scope`) {#access-key-scope} This field controls the [default allowed operations](/docs/iam/manage-access-key/#default-allowed-operations) -on the key. A standard key can create buckets, list buckets, and create access -keys and IAM policies even with no bucket role. +on the key. A standard key can create buckets, list buckets, and manage its own +access keys and IAM policies, even with no bucket role. | Value | What it means | | -------------------- | -------------------------------------------------------- | @@ -82,67 +91,172 @@ keys and IAM policies even with no bucket role. | `no_default_allow` | The key does not receive the default allowed operations. | If you omit `access_key_scope`, the key uses `standard`. You can set the field -on [Create Access Key](/docs/partner-integrations/api/tigris-create-access-key) +on [Provision](/docs/partner-integrations/api/tigris-provisioning), +[Create Access Key](/docs/partner-integrations/api/tigris-create-access-key), and [Update Access Key](/docs/partner-integrations/api/tigris-update-access-key). If you omit the field on update, the current scope stays unchanged. -## How the fields interact +A key that creates a bucket becomes the owner of that bucket, and an owner can +do every operation on it. Use `no_default_allow` for keys that you give to your +users, so that they cannot create buckets that they own. + +## The Provisioned Access Key + +[Provision](/docs/partner-integrations/api/tigris-provisioning) returns an +access key, and that key is the **owner** of the bucket it provisions. The owner +can do every operation on the bucket. It can delete the bucket, change its +settings, and turn off soft delete. Bucket roles, IAM policies, and +`access_key_scope` cannot limit what an owner can do on its bucket. + +Keep the provisioned key in your backend, or delete it. Give your users a +separate key that has only the access they need. See +[Give Users Data Access Without Bucket Admin](#give-users-data-access-without-bucket-admin). + +Each Provision call creates a new owner key. If your backend manages the bucket +with the Partner API, it does not need this key. You can delete the key with +[Delete Access Key](/docs/partner-integrations/api/tigris-delete-access-key) +after Provision. The Partner API calls for the bucket continue to work, and no +access key owns the bucket. + +If your users already have the provisioned key, see +[Move Users Off the Provisioned Key](#move-users-off-the-provisioned-key). + +## How Tigris Evaluates a Request + +Tigris checks each S3 request in this order. It stops at the first step that +gives a result. + +| Step | Check | Result | +| ---- | ------------------------------------------------------------------------- | ------------- | +| 1 | The bucket has delete protection and the request deletes a bucket or data | Deny | +| 2 | The key has `{"bucket_name": "*", "role": "Admin"}` | Allow | +| 3 | The key owns the bucket | Allow | +| 4 | A bucket role on the key permits the operation | Allow | +| 5 | An IAM policy on the key matches. A `Deny` statement wins over an `Allow` | Deny or allow | +| 6 | The key uses `standard` and the operation is a default allowed operation | Allow | +| 7 | No step gave a result | Deny | + +A policy cannot take away an operation that steps 2 to 4 allow. For example, a +`Deny` on `s3:DeleteBucket` has no effect on a key with the `Editor` role, +because the role allows the delete at step 4. To limit a key, give it a smaller +role, or give it no role and grant access with a policy. + +## Permission Recipes -| Scenario | `user_role` | `buckets_roles` | `access_key_scope` | Result | -| --------------------- | ----------- | ---------------------------------------- | ------------------ | ------------------------------------------------- | -| **Developer uploads** | `Member` | `user-uploads: ReadWrite` | `no_default_allow` | User manages own key, can read/write their bucket | -| **Platform admin** | `Admin` | `*: Admin` | `standard` | Full management + full S3 access | -| **CI/CD pipeline** | `Member` | `artifacts: ReadOnly` | `no_default_allow` | Automated reads, no access-key or IAM management | -| **Mixed access** | `Member` | `assets: ReadOnly`, `uploads: ReadWrite` | `no_default_allow` | Read shared content, write user content | +Each recipe shows one request. Replace the IDs and bucket names with your own. -## Common Access Patterns +The recipes that grant a bucket role use `user_role: "Admin"`, so that your +backend can grant a role on any bucket in the org. You can use `Member` instead +when `user_id` is the user that provisioned the bucket. -### Read-only access to a bucket +### Give Users Data Access Without Bucket Admin + +Use this recipe when your users read and write their own data and your backend +manages the buckets. ```http -POST /v1/providers/{provider_id}/orgs/{org_id}/access-keys +POST /v1/providers/{provider_id}/orgs/{org_id}/key Content-Type: application/json { "user_id": "user-123", - "user_role": "Member", + "user_role": "Admin", + "name": "user-123-data", "access_key_scope": "no_default_allow", "buckets_roles": [ - { "bucket_name": "assets", "role": "ReadOnly" } + { "bucket_name": "user-data", "role": "ReadWrite" } ] } ``` -### Read/write access to a bucket +The key can read, write, and delete objects in `user-data`. It cannot delete the +bucket, change bucket settings, turn off soft delete, create buckets, or create +access keys. + +### Move Users Off the Provisioned Key + +Use this recipe when your users already have the provisioned key. You cannot +move the ownership of a bucket to a different key. You must replace the secret +of the provisioned key instead. + +With the provisioned key, a user can create more access keys. These keys +continue to work after you rotate the provisioned key. You must also delete +them. + +1. Create a key for the user with the + [Give Users Data Access Without Bucket Admin](#give-users-data-access-without-bucket-admin) + recipe. Give the new key to the user. +2. Rotate the provisioned key with + [Rotate Access Key](/docs/partner-integrations/api/tigris-rotate-access-key): + + ```http + POST /v1/providers/{provider_id}/orgs/{org_id}/key/rotate + Content-Type: application/json + + { + "user_id": "user-123", + "user_role": "Admin", + "id": "tid_provisioned_key_id" + } + ``` + +3. Keep the new secret from the response in your backend. +4. Get all of the access keys in the org with + [List Access Keys](/docs/partner-integrations/api/tigris-list-access-keys) + and `user_role: "Admin"`. +5. If a key is not in the records of your backend, delete it with + [Delete Access Key](/docs/partner-integrations/api/tigris-delete-access-key). + +The old secret and the deleted keys can continue to work for up to 15 minutes. + +### Read-Only Access to One Bucket ```http -POST /v1/providers/{provider_id}/orgs/{org_id}/access-keys +POST /v1/providers/{provider_id}/orgs/{org_id}/key Content-Type: application/json { "user_id": "user-123", - "user_role": "Member", + "user_role": "Admin", "access_key_scope": "no_default_allow", "buckets_roles": [ - { "bucket_name": "uploads", "role": "ReadWrite" } + { "bucket_name": "assets", "role": "ReadOnly" } ] } ``` -This key can read and write objects in `uploads`. It cannot list buckets or -create buckets unless a policy grants those actions. It cannot manage access -keys or IAM policies. +The key can read and list objects in `assets`. It cannot write or delete +objects, and it cannot list or create buckets. -### Mixed permissions across buckets +### Read-Only Access to All Buckets ```http -POST /v1/providers/{provider_id}/orgs/{org_id}/access-keys +POST /v1/providers/{provider_id}/orgs/{org_id}/key +Content-Type: application/json + +{ + "user_id": "reporting", + "user_role": "Admin", + "access_key_scope": "no_default_allow", + "buckets_roles": [ + { "bucket_name": "*", "role": "ReadOnly" } + ] +} +``` + +The key can read every bucket in the org, including buckets created later. Only +a `user_role: "Admin"` call can grant a role on `"*"`. + +### Different Access per Bucket + +```http +POST /v1/providers/{provider_id}/orgs/{org_id}/key Content-Type: application/json { "user_id": "user-123", - "user_role": "Member", + "user_role": "Admin", "access_key_scope": "no_default_allow", "buckets_roles": [ { "bucket_name": "assets", "role": "ReadOnly" }, @@ -151,14 +265,61 @@ Content-Type: application/json } ``` -### Full admin key for org owner +The key can read `assets`, and it can read and write `uploads`. + +### Upload-Only Key + +Use a policy for this recipe, because no bucket role allows uploads without +reads. The key gets no bucket role, so Tigris evaluates the policy. + +```http +POST /v1/providers/{provider_id}/orgs/{org_id}/key +Content-Type: application/json + +{ + "user_id": "user-123", + "name": "uploader", + "access_key_scope": "no_default_allow", + "create_policies": [ + { + "name": "uploads-put-only", + "document": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": ["s3:PutObject", "s3:AbortMultipartUpload"], + "Resource": ["arn:aws:s3:::uploads/*"] + } + ] + } + } + ] +} +``` + +The key can upload objects to `uploads`, with multipart uploads too. It cannot +read, list, or delete objects. It can overwrite an object that has the same +name. + +`s3:PutObject` covers the create, upload part, and complete steps of a multipart +upload. Tigris rejects `s3:CreateMultipartUpload` and `s3:UploadPart` in a +policy. + +Policy names are unique in the org. To give the same policy to more keys, create +it one time, then pass its name in `attach_policies`. + +### Backend Admin Key + +Your backend can use the provisioned key for its bucket. To manage all buckets +in the org from one key, create an org admin key: ```http -POST /v1/providers/{provider_id}/orgs/{org_id}/access-keys +POST /v1/providers/{provider_id}/orgs/{org_id}/key Content-Type: application/json { - "user_id": "admin-user", + "user_id": "platform-backend", "user_role": "Admin", "buckets_roles": [ { "bucket_name": "*", "role": "Admin" } @@ -166,18 +327,102 @@ Content-Type: application/json } ``` -For most integrations, `user_role: "Member"` with per-bucket `ReadOnly` or -`ReadWrite` roles covers what you need. Use `Editor` only when the integration -must manage bucket configuration. Reserve `Admin` for org owners who need to -manage other users' keys or org-level settings. +:::warning -## Fine-Grained Access with IAM Policies +Keep this key in your backend. Do not give it to your users. The key can delete +every bucket in the org. + +::: + +### Protect Buckets From Accidental Deletion -For access control more granular than per-bucket roles, like restricting to -object prefixes, IP ranges, or time windows, use -[IAM policies](/docs/iam/policies/). Policies are evaluated after role checks, -so they can further restrict what a role allows. +Turn on [soft delete](/docs/buckets/soft-delete/) when you provision the bucket: + +```http +POST /v1/providers/{provider_id}/orgs/{org_id}/provision +Content-Type: application/json + +{ + "bucket_name": "user-data", + "org_name": "Acme Corp", + "user_id": "user-123", + "bucket_options": { + "soft_delete": { "enabled": true, "retention_days": 30 } + } +} +``` + +For an existing bucket, use +[Set Soft Delete](/docs/partner-integrations/api/tigris-set-soft-delete). + +When a user deletes the bucket, it moves to the deleted buckets list. Use +[List Deleted Buckets](/docs/partner-integrations/api/tigris-list-deleted-buckets) +to find it, and +[Restore Bucket](/docs/partner-integrations/api/tigris-restore-bucket) to bring +it back. + +A soft-deleted bucket stays until you restore it or +[delete it permanently](/docs/partner-integrations/api/tigris-purge-bucket). It +counts toward storage usage until then. + +Soft delete protects the bucket from a usual delete request. It does not stop a +key that can change bucket settings: + +- The bucket owner, `Editor` keys, and org admin keys can turn off soft delete. +- These keys can also permanently delete a soft-deleted bucket over S3. +- A `ReadWrite` key cannot do these operations. + +### Change Bucket Settings for Your Users + +No bucket role allows bucket settings without bucket deletion. `Editor` includes +`DeleteBucket`, and a policy cannot take it away (see +[How Tigris Evaluates a Request](#how-tigris-evaluates-a-request)). + +Keep your users on `ReadWrite`, and change bucket settings from your backend +with the Partner API: + +- [Update Bucket](/docs/partner-integrations/api/tigris-update-bucket) for + public access, storage class, regions, and object notifications +- [Set Lifecycle Rules](/docs/partner-integrations/api/tigris-set-lifecycle-rules) +- [Attach a Custom Domain](/docs/partner-integrations/api/tigris-set-custom-domain) +- [Set Soft Delete](/docs/partner-integrations/api/tigris-set-soft-delete) + +### Rotate or Revoke a Key + +To replace a leaked secret, call +[Rotate Access Key](/docs/partner-integrations/api/tigris-rotate-access-key). It +returns a new secret and keeps the key ID, so the key keeps its roles, policies, +and bucket ownership. + +To revoke a key, call +[Delete Access Key](/docs/partner-integrations/api/tigris-delete-access-key). +Deleting a key does not delete the buckets that it owns. + +:::note + +After you rotate or delete a key, the old secret can continue to work for up to +15 minutes. After you change the bucket roles or the scope of a key, the old +access can also continue for up to 15 minutes. + +::: + +A `Member` call can rotate or delete only the keys of its `user_id`. A +`user_role: "Admin"` call can rotate or delete any key in the org. + +## Fine-Grained Access with IAM Policies -**Important:** `Admin` role bypasses policy evaluation entirely. If you need -policies to apply, use `Member` with `Editor`, `ReadWrite`, or `ReadOnly` roles -instead. +For access that bucket roles cannot give, use +[IAM policies](/docs/iam/policies/). You can create a policy with +[Create Policy](/docs/partner-integrations/api/tigris-create-policy) and attach +it with `attach_policies` on Create Access Key or `add_policies` on Update +Access Key. You can also create and attach a policy in one call with +`create_policies`. + +Policies only add access. Tigris reads them only when the key's bucket roles and +bucket ownership do not already allow the operation (see +[How Tigris Evaluates a Request](#how-tigris-evaluates-a-request)): + +- To grant access with a policy, give the key no bucket role on that bucket. +- A `Deny` statement blocks only access that a policy or a default allowed + operation gives. It does not block access that a bucket role, bucket + ownership, or the `"*"` `Admin` role gives. diff --git a/docs/partner-integrations/architecture.mdx b/docs/partner-integrations/architecture.mdx index fac8b574..a8a8957d 100644 --- a/docs/partner-integrations/architecture.mdx +++ b/docs/partner-integrations/architecture.mdx @@ -27,7 +27,7 @@ graph TD | **Provider** | Your partner account. This identifies your platform and holds your signing key for API authentication. You manage all customer organizations through this provider. | | **Organization** | An isolated container for a single tenant/customer. Each organization contains its own buckets, users, access keys, and has separate usage tracking and billing. | | **Bucket** | S3-compatible storage container within an organization. Organizations can have multiple buckets. | -| **User** | An identity within an organization with either `Admin` or `Member` role. Users can create access keys and manage resources within their organization. | +| **User** | A user ID from your system, passed as `user_id`. Each Partner API call says whether the user is an `Admin` or a `Member` with `user_role`. | | **Access Key** | S3-compatible credentials (access key ID + secret) scoped to an organization. Can optionally be restricted to specific buckets within that org. | ## Organizations Explained @@ -76,18 +76,21 @@ Content-Type: application/json The `org_id` should be a unique identifier for that tenant in your system (e.g., `tenant-abc123` or `customer-{uuid}`). -**2. Store the returned credentials** - The response includes an access key and -secret scoped to that organization: +**2. Store the returned credentials** - The response includes an access key that +owns the new bucket: ```json { + "bucket_name": "user-data", "access_key_id": "tid_...", - "secret_access_key": "tsec_...", - "bucket": "user-data", - "org_id": "tenant-abc123" + "secret_access_key": "tsec_..." } ``` +This key has full control of the bucket, including deleting it. Keep it in your +backend or delete it, and give your users a key with less access. See +[The Provisioned Access Key](/docs/partner-integrations/access-control#the-provisioned-access-key). + **3. Create additional buckets** as needed using the Partner API or standard S3 CreateBucket API. All buckets remain isolated within the tenant's organization. @@ -126,9 +129,9 @@ Content-Type: application/json } ``` -The `user_role` field controls what this user can do through management -endpoints. See [Access Control](/docs/partner-integrations/access-control) for -details on how roles and permissions work. +The `user_role` field applies to this call only. See +[Access Control](/docs/partner-integrations/access-control) for details on how +roles and permissions work. ### Offboarding Tenants @@ -160,11 +163,40 @@ Content-Type: application/json 3. Delete all buckets using the bucket deletion API 4. The organization remains for historical billing records +## Common Questions + +### Which `user_id` Should I Use? + +Each access key and each provisioned bucket belongs to a `user_id`. Two models +work: + +- **One backend user per organization**, such as your service account. All keys + and buckets belong to that user, so `Member` calls can manage all of them. +- **One user per person in your system.** Each person's keys stay separate, and + List Access Keys with `Member` returns only that person's keys. To grant a + role on a bucket that a different user provisioned, pass `user_role: "Admin"`. + +### Is `org_id` Unique Across Tigris? + +No. An `org_id` is unique only within your provider. Use your own account or +tenant ID. + +### Are Bucket Names Unique per Organization? + +No. Bucket names are global across all Tigris users, as in AWS S3. To prevent a +name conflict, add a prefix such as your `org_id`, or generate the names. + +### Which Units Do Usage and Invoices Use? + +Invoices show storage in GiB-month and data transfer in GiB. One GiB is 1024³ +bytes. Each metric from the usage API includes its own `unit`. The quota field +`org_quota.limit_bytes` is a number of bytes. + ## Next Steps - **[Access Control](/docs/partner-integrations/access-control)** -- Learn how - to use `user_role`, `buckets_roles`, and `access_key_scope` to control what - your tenants' access keys can do + to use `user_role`, `buckets_roles`, and `access_key_scope`, with permission + recipes for common setups - **[Partner Integrations API Reference](/docs/partner-integrations/api/)** -- Complete API documentation for all partner endpoints diff --git a/src/components/diagrams/data/partner-access-control.json b/src/components/diagrams/data/partner-access-control.json index 24fe7be8..c1a1b89e 100644 --- a/src/components/diagrams/data/partner-access-control.json +++ b/src/components/diagrams/data/partner-access-control.json @@ -27,7 +27,7 @@ "id": "create-key-text", "x": 485, "y": 60, - "text": "POST /access-keys", + "text": "POST /key", "fontSize": 18, "fontFamily": 1, "strokeColor": "#0A171E" @@ -170,7 +170,7 @@ "id": "admin-mgmt-desc", "x": 60, "y": 317, - "text": "All keys, org settings, users", + "text": "Any key; any bucket role", "fontSize": 14, "fontFamily": 1, "strokeColor": "#8fa3b0" @@ -203,7 +203,7 @@ "id": "member-mgmt-desc", "x": 60, "y": 402, - "text": "Own keys only", + "text": "Own keys; own buckets only", "fontSize": 14, "fontFamily": 1, "strokeColor": "#8fa3b0" @@ -370,7 +370,7 @@ "id": "admin-s3-desc", "x": 470, "y": 521, - "text": "All ops, bypasses all checks", + "text": "All ops, all buckets (\"*\")", "fontSize": 13, "fontFamily": 1, "strokeColor": "#8fa3b0" @@ -428,7 +428,7 @@ "id": "standard-scope-desc", "x": 880, "y": 321, - "text": "Create/list buckets; limited\nkey and policy management", + "text": "Create/list buckets; manage\nown keys and policies", "fontSize": 13, "fontFamily": 1, "strokeColor": "#8fa3b0"