tigris-security-access-control — Claude Code skill
This skill guides Tigris object-storage access control: keys, roles, CORS, and presigned URLs. Use it when securing buckets or reviewing access settings.
npx skills add tigrisdata/skills --skill tigris-security-access-control -a claude-codeWhat tigris-security-access-control does
The skill covers Tigris access-key creation and revocation, bucket-scoped permissions, and the Editor and ReadOnly roles. It also addresses public versus private buckets, CORS rules, and presigned URL safety.
It includes Tigris CLI commands for key and CORS management, cors.json examples, and checks for tid_ and tsec_ credentials in a repository. A secret access key is displayed only when created, so save it immediately.
Tigris CLI is required before use: tigris help || npm install -g @tigrisdata/cli. Browser uploads need CORS configuration, especially when using presigned PUT URLs.
What it helps with
- create an application access key
- assign a bucket role to a key
- revoke an old access key
- apply CORS from
cors.json - inspect a key's bucket access
Example prompts for the agent
- Configure CORS for the
my-app-uploadsbucket usingcors.json. - Create a new key for
my-app-uploadsand assign theEditorrole. - Check which buckets the
tid_xxxkey can access.
How to install tigris-security-access-control
1Skills CLI (Vercel)
npx skills add tigrisdata/skills --skill tigris-security-access-control -a claude-code2Manually: put the files in place
~/.claude/skills/tigris-security-access-control/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/tigris-security-access-control/
1Skills CLI (Vercel)
npx skills add tigrisdata/skills --skill tigris-security-access-control -a codex2Manually: put the files in place
.agents/skills/tigris-security-access-control/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add tigrisdata/skills --skill tigris-security-access-control -a cursor2Manually: put the files in place
.cursor/skills/tigris-security-access-control/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install tigrisdata/skills tigris-security-access-control2Manually: put the files in place
.github/skills/tigris-security-access-control/SKILL.md1Skills CLI (Vercel)
npx skills add tigrisdata/skills --skill tigris-security-access-control -a gemini-cli2Platform CLI
gemini skills install https://github.com/tigrisdata/skills --path skills/tigris-security-access-controlManually: put the files in place
.devin/skills/tigris-security-access-control/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add tigrisdata/skills --skill tigris-security-access-control -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about tigris-security-access-control
How do I install tigris-security-access-control in Claude Code?
Run npx skills add tigrisdata/skills --skill tigris-security-access-control -a claude-code, then run npx skills add tigrisdata/skills --skill tigris-security-access-control -a claude-code again. The skill file is at ~/.claude/skills/tigris-security-access-control/SKILL.md.
What does tigris-security-access-control do?
It covers Tigris access keys, bucket roles, CORS configuration, public and private buckets, and presigned URL security.
What is the difference between Editor and ReadOnly?
Editor permits reads, writes, and deletes. ReadOnly permits reads only.
Source text
SKILL.md · MIT
---
name: tigris-security-access-control
description: Use when configuring CORS, rotating access keys, setting bucket policies, or securing Tigris storage — covers key lifecycle, roles, CORS rules, presigned URL security, audit checklist
---
# Tigris Security & Access Control
Configure access keys, CORS rules, bucket visibility, and presigned URL security for Tigris object storage. Covers key lifecycle management, role-based access, and security auditing.
## Prerequisites
**Before doing anything else**, install the Tigris CLI if it's not already available:
```bash
tigris help || npm install -g @tigrisdata/cli
```
If you need to install it, tell the user: "I'm installing the Tigris CLI (`@tigrisdata/cli`) so we can work with Tigris object storage."
## Quick Reference
| Operation | Command |
|-----------|---------|
| Create key | `tigris access-keys create "my-key"` |
| List keys | `tigris access-keys list` |
| Assign to bucket | `tigris access-keys assign <tid> --bucket <name> --role Editor` |
| Revoke key | `tigris access-keys delete <tid>` |
| Set CORS | `tigris buckets cors set <bucket> --config cors.json` |
| Get CORS | `tigris buckets cors get <bucket>` |
| Remove CORS | `tigris buckets cors delete <bucket>` |
---
## Access Key Lifecycle
### Create
```bash
tigris access-keys create "production-app-key"
# Output:
# Access Key ID: tid_xxx
# Secret Access Key: tsec_yyy ← shown ONLY once, save immediately
```
### Assign to Bucket
```bash
# Editor: read + write + delete
tigris access-keys assign tid_xxx --bucket my-app-uploads --role Editor
# ReadOnly: read only
tigris access-keys assign tid_xxx --bucket my-app-uploads --role ReadOnly
```
| Role | Read | Write | Delete | Use When |
|------|------|-------|--------|----------|
| `Editor` | Yes | Yes | Yes | App servers that upload/modify files |
| `ReadOnly` | Yes | No | No | Services that only read/serve files |
### Scope Keys Narrowly
Create separate keys for different concerns:
```bash
# Key for the app server (read/write to uploads bucket)
tigris access-keys create "app-server"
tigris access-keys assign tid_app --bucket app-uploads --role Editor
# Key for the CDN/read service (read-only)
tigris access-keys create "cdn-reader"
tigris access-keys assign tid_cdn --bucket app-uploads --role ReadOnly
# Key for backups (write to backup bucket only)
tigris access-keys create "backup-writer"
tigris access-keys assign tid_bak --bucket app-backups --role Editor
```
### Rotate Keys (Zero Downtime)
```bash
# 1. Create new key
tigris access-keys create "production-app-key-v2"
tigris access-keys assign tid_new --bucket my-app-uploads --role Editor
# 2. Update application environment with new key
# (deploy with new TIGRIS_STORAGE_ACCESS_KEY_ID / SECRET)
# 3. Verify app works with new key
# 4. Revoke old key
tigris access-keys delete tid_old
```
### List and Audit
```bash
# List all access keys
tigris access-keys list
# Check which buckets a key can access
tigris access-keys info tid_xxx
```
---
## CORS Configuration
CORS is required for browser-based uploads (direct uploads, presigned PUT URLs).
### Set CORS Rules
```bash
tigris buckets cors set my-app-uploads --config cors.json
```
### Development (Localhost)
```json
{
"CORSRules": [
{
"AllowedOrigins": ["http://localhost:3000", "http://localhost:5173"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag", "Content-Length"],
"MaxAgeSeconds": 3600
}
]
}
```
### Production (Specific Domain)
```json
{
"CORSRules": [
{
"AllowedOrigins": ["https://myapp.com", "https://www.myapp.com"],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["Content-Type", "Content-MD5", "Content-Disposition"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]
}
```
### Combined Dev + Production
```json
{
"CORSRules": [
{
"AllowedOrigins": [
"https://myapp.com",
"https://www.myapp.com",
"http://localhost:3000"
],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag", "Content-Length"],
"MaxAgeSeconds": 3600
}
]
}
```
### Permissive (Any Origin)
```json
{
"CORSRules": [
{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 86400
}
]
}
```
**Warning:** Only use `"*"` origins for truly public, read-only content. Never allow `PUT`/`DELETE` from any origin.
### Verify CORS
```bash
# Check current CORS config
tigris buckets cors get my-app-uploads
# Test with curl
curl -I -H "Origin: https://myapp.com" \
-H "Access-Control-Request-Method: PUT" \
-X OPTIONS \
https://my-app-uploads.t3.storage.dev/test
```
---
## Public vs Private Buckets
| Setting | Who Can Read | URL Access | Use For |
|---------|-------------|------------|---------|
| Private (default) | Only authenticated requests | Presigned URLs | User documents, sensitive files |
| Public | Anyone with URL | Direct URL | Static assets, public images, CDN content |
```bash
# Create public bucket
tigris buckets create my-public-assets --public
# Create private bucket (default)
tigris buckets create my-private-docs
```
---
## Presigned URL Security
### Best Practices
| Parameter | Recommendation |
|-----------|---------------|
| Expiration (download) | 5-60 minutes for most use cases |
| Expiration (upload) | 5-15 minutes |
| Scope | One URL per file, one operation per URL |
```typescript
import { getPresignedUrl } from "@tigrisdata/storage";
// Short-lived download URL
const { data } = await getPresignedUrl("documents/report.pdf", {
operation: "get",
expiresIn: 300, // 5 minutes
});
// Short-lived upload URL with content type restriction
const { data } = await getPresignedUrl("uploads/photo.jpg", {
operation: "put",
expiresIn: 600,
contentType: "image/jpeg", // Client must upload this type
});
```
### Never Do
- Set expiration longer than 24 hours
- Generate presigned URLs for entire bucket prefixes
- Share presigned URLs in public channels (they're secrets)
- Use presigned URLs as permanent links (use public bucket URLs instead)
---
## Environment Variable Security
```bash
# .env (never commit this file)
TIGRIS_STORAGE_ACCESS_KEY_ID=tid_xxx
TIGRIS_STORAGE_SECRET_ACCESS_KEY=tsec_yyy
```
```bash
# .gitignore (must include)
.env
.env.local
.env.*.local
```
For CI/CD, use your platform's secrets management:
```bash
# GitHub Actions
gh secret set TIGRIS_STORAGE_ACCESS_KEY_ID
gh secret set TIGRIS_STORAGE_SECRET_ACCESS_KEY
# Vercel
vercel env add TIGRIS_STORAGE_ACCESS_KEY_ID
# Fly.io
fly secrets set TIGRIS_STORAGE_ACCESS_KEY_ID=tid_xxx
```
---
## Security Audit Checklist
- [ ] **No keys in code** — search for `tid_` and `tsec_` in your repo
- [ ] **`.env` in `.gitignore`** — credentials never committed
- [ ] **Keys scoped to buckets** — no unassigned keys with global access
- [ ] **Roles match need** — read-only services use `ReadOnly` role
- [ ] **CORS not overly permissive** — no `"*"` origin with write methods
- [ ] **Presigned URLs have short expiry** — under 1 hour for most cases
- [ ] **Unused keys revoked** — no stale keys from former team members or old deployments
- [ ] **Separate keys per environment** — dev/staging/production use different keys
---
## Key Compromise Response
If an access key is exposed (committed to git, leaked in logs, etc.):
```bash
# 1. Immediately revoke the compromised key
tigris access-keys delete tid_compromised
# 2. Create a new key
tigris access-keys create "replacement-key"
tigris access-keys assign tid_new --bucket my-bucket --role Editor
# 3. Update all deployments with the new key
# (update .env, CI/CD secrets, deployment configs)
# 4. Audit access — check for unauthorized uploads/downloads
tigris ls t3://my-bucket --recursive -l | sort -k4 -r | head -50
# 5. If key was committed to git, rotate and consider the entire
# git history compromised — use git-filter-repo to remove it
```
---
## Critical Rules
**Always:** Create separate keys per environment and concern | Assign keys to specific buckets with minimum required role | Rotate keys periodically (quarterly recommended) | Set CORS to specific origins in production | Use short-lived presigned URLs
**Never:** Commit keys to git | Use a single key for all environments | Set CORS to `"*"` with write methods | Share presigned URLs publicly | Keep unused keys active
---
## Known Issues
| Problem | Fix |
|---------|-----|
| CORS preflight fails | Check `AllowedOrigins` includes your exact origin (with protocol) |
| "Access denied" after key rotation | Ensure new key is assigned to bucket with correct role |
| Secret key lost | Cannot recover — create new key and reassign |
| Browser upload fails silently | Check CORS config includes `PUT` in `AllowedMethods` |
---
## Related Skills
- **file-storage** — CLI setup and access key creation
- **tigris-s3-migration** — CORS and credential setup during migration
## Official Documentation
- Tigris: https://www.tigrisdata.com/docs/
© tigrisdata · MIT · tigrisdata/skills