Acesso Restrito a Buckets no Storin (Somente Escrita e Somente Leitura)
⚠️ Todas as configurações deste manual são exemplos. Adapte nomes de buckets, perfis e User IDs conforme o seu ambiente.
📌 Visão Geral
Este guia mostra como compartilhar um bucket do Storin com acessos restritos, por exemplo:
- uma credencial que só envia arquivos (write-only), útil para aplicações que fazem upload de backups ou logs;
- uma credencial que só lê e lista arquivos (read-only), útil para auditoria, consulta ou processamento.
O controle é feito por Bucket Policy.
Os exemplos deste guia usam a AWS CLI, mas o mesmo procedimento pode ser feito via API S3, MinIO Client (mc) ou qualquer outra ferramenta compatível com S3. A Bucket Policy (JSON) é a mesma; muda apenas o comando usado para aplicá-la.
🧠 Como o Storin aplica as permissões
No Storin, as permissões não são aplicadas pela Access Key ou Secret Key individualmente. Elas são aplicadas pelo User ID (identidade S3) ao qual a credencial pertence.
Na prática:
- Cada projeto do painel possui uma identidade S3, com um User ID próprio.
- Todas as Access Keys geradas dentro do mesmo projeto usam o mesmo User ID e, portanto, têm exatamente as mesmas permissões.
- As chaves servem apenas para autenticar a identidade. Quem define o que pode ou não ser feito é o User ID referenciado na policy.
Para ter perfis de acesso diferentes (dono, somente escrita, somente leitura), cada perfil precisa de um User ID diferente, ou seja, um projeto diferente.
Gerar uma nova Access Key/Secret Key no mesmo projeto não cria uma nova identidade.
Exemplo de estrutura
| Projeto | User ID | Uso |
|---|---|---|
| Projeto principal | USER_OWNER | Proprietário do bucket |
| Projeto Writer | USER_WRITER | Somente escrita |
| Projeto Reader | USER_READER | Somente leitura |
A Bucket Policy é configurada no bucket do Projeto principal, referenciando USER_WRITER e USER_READER.
🧰 Pré-requisitos
- Um bucket já criado no projeto principal (o dono do bucket).
- Uma ferramenta compatível com S3. Neste guia usamos a AWS CLI; caso ainda não tenha configurado, siga o guia Configurando a AWS CLI com o Storin.
jqinstalado (opcional, usado para validar o JSON da policy antes de aplicar).
🆔 Parte 1 – Criando as identidades (User IDs)
Repita os passos abaixo uma vez para cada perfil restrito (um projeto para o Writer e outro para o Reader).
Passo 1 – Criar um novo projeto
No painel, crie um novo projeto. Ele pode estar na mesma conta ou em uma conta diferente da que contém o bucket.

Passo 2 – Inicializar a identidade S3
A identidade S3 do projeto é gerada no primeiro uso do Object Storage. Para inicializá-la, crie um bucket temporário nesse projeto e, em seguida, apague-o.

O bucket temporário serve apenas para gerar a identidade. Ele pode ser excluído logo depois, sem impacto no User ID.
Passo 3 – Copiar o User ID
Acesse a aba Acessos do projeto e copie o User ID exibido.

Passo 4 – Gerar a Access Key e Secret Key
Ainda na aba Acessos, gere a Access Key e a Secret Key desse projeto e guarde-as em local seguro. Elas serão usadas pela aplicação ou pessoa que terá o acesso restrito.

A Secret Key é exibida apenas no momento da criação. Guarde-a imediatamente em um local seguro, como um cofre de senhas.
Ao final desta parte, você terá:
| Perfil | User ID | Credenciais |
|---|---|---|
| Writer | <WRITER_ID> | Access Key + Secret Key |
| Reader | <READER_ID> | Access Key + Secret Key |
⚙️ Parte 2 – Configurando a AWS CLI
Configure um perfil para cada identidade (dono, writer e reader).
Arquivo ~/.aws/config
[profile storin-owner]
region = sp1
output = json
request_checksum_calculation = when_required
response_checksum_validation = when_required
endpoint_url = https://sp1-s3.saveincloud.io
[profile storin-writer]
region = sp1
output = json
request_checksum_calculation = when_required
response_checksum_validation = when_required
endpoint_url = https://sp1-s3.saveincloud.io
[profile storin-reader]
region = sp1
output = json
request_checksum_calculation = when_required
response_checksum_validation = when_required
endpoint_url = https://sp1-s3.saveincloud.io
Arquivo ~/.aws/credentials
[storin-owner]
aws_access_key_id = <ACCESS_KEY_OWNER>
aws_secret_access_key = <SECRET_KEY_OWNER>
[storin-writer]
aws_access_key_id = <ACCESS_KEY_WRITER>
aws_secret_access_key = <SECRET_KEY_WRITER>
[storin-reader]
aws_access_key_id = <ACCESS_KEY_READER>
aws_secret_access_key = <SECRET_KEY_READER>
As linhas request_checksum_calculation e response_checksum_validation são obrigatórias na AWS CLI 2.25 ou superior. Sem elas, todo upload falha com ValidationError.
Ajuste o endpoint_url conforme a região do seu bucket (por exemplo, https://sp1-s3.saveincloud.io ou https://bsb1-s3.saveincloud.io).
📝 Parte 3 – Criando e aplicando a Bucket Policy
Passo 1 – Criar o arquivo da policy
Crie um arquivo chamado policy.json com o conteúdo abaixo:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowWrite",
"Effect": "Allow",
"Principal": { "CanonicalUser": "<WRITER_ID>" },
"Action": [
"s3:PutObject",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts"
],
"Resource": "arn:aws:s3:::<BUCKET>/*"
},
{
"Sid": "DenyReadForWriter",
"Effect": "Deny",
"Principal": { "CanonicalUser": "<WRITER_ID>" },
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": "arn:aws:s3:::<BUCKET>/*"
},
{
"Sid": "AllowReadObjects",
"Effect": "Allow",
"Principal": { "CanonicalUser": "<READER_ID>" },
"Action": ["s3:GetObject", "s3:GetObjectVersion"],
"Resource": "arn:aws:s3:::<BUCKET>/*"
},
{
"Sid": "AllowListForReader",
"Effect": "Allow",
"Principal": { "CanonicalUser": "<READER_ID>" },
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::<BUCKET>", "arn:aws:s3:::<BUCKET>/*"]
}
]
}
Substitua:
| Variável | Valor |
|---|---|
<WRITER_ID> | User ID do projeto Writer |
<READER_ID> | User ID do projeto Reader |
<BUCKET> | Nome do bucket que será compartilhado |
O que cada bloco faz
| Sid | Perfil | Efeito |
|---|---|---|
AllowWrite | Writer | Permite enviar objetos, inclusive uploads multipart |
DenyReadForWriter | Writer | Bloqueia leitura e exclusão, inclusive dos objetos que ele mesmo enviou |
AllowReadObjects | Reader | Permite baixar objetos e suas versões |
AllowListForReader | Reader | Permite listar o conteúdo do bucket |
Passo 2 – Aplicar a policy
A policy deve ser aplicada com a credencial do dono do bucket. Exemplo com AWS CLI:
jq . policy.json && aws --profile storin-owner s3api put-bucket-policy \
--bucket <BUCKET> \
--policy file://policy.json
O jq valida o JSON antes do envio. Se houver erro de sintaxe, o comando para antes de aplicar a policy.
Para conferir a policy aplicada:
aws --profile storin-owner s3api get-bucket-policy --bucket <BUCKET>
❗ Regras obrigatórias
Estas regras valem para qualquer ferramenta usada para aplicar a policy.
CanonicalUserO Principal precisa usar CanonicalUser com o User ID em hexadecimal. As formas abaixo não funcionam no Storin e podem retornar 403:
"Principal": { "AWS": "<id>" }
"Principal": { "AWS": "arn:aws:iam:::user/<id>" }
DenyReadForWriter é obrigatórioQuem faz o PUT de um objeto se torna dono desse objeto e consegue lê-lo por ACL. Sem o Deny explícito, o Writer consegue ler tudo o que ele mesmo enviou.
O proprietário do bucket sempre tem acesso total, pois a ownership tem prioridade sobre a policy. Por isso, a credencial restrita precisa pertencer a uma identidade diferente da do dono, ou seja, a outro projeto.
✅ Parte 4 – Validando as permissões
Os testes abaixo usam a AWS CLI. Com outra ferramenta, execute as operações equivalentes (upload, download, listagem e exclusão) com cada credencial e compare com a tabela de resultado esperado.
Crie um arquivo de teste:
echo "teste" > /tmp/t.txt
Writer (somente escrita)
# Deve PASSAR
aws --profile storin-writer s3api put-object --bucket <BUCKET> --key wr.txt --body /tmp/t.txt
# Devem retornar 403 (AccessDenied)
aws --profile storin-writer s3api get-object --bucket <BUCKET> --key wr.txt /tmp/x.txt
aws --profile storin-writer s3api list-objects-v2 --bucket <BUCKET>
aws --profile storin-writer s3api delete-object --bucket <BUCKET> --key wr.txt
Teste o GET do Writer sobre um objeto criado por ele mesmo (como o wr.txt acima). Esse é o cenário que comprova que o DenyReadForWriter está funcionando.
Reader (somente leitura)
# Devem PASSAR
aws --profile storin-reader s3api get-object --bucket <BUCKET> --key wr.txt /tmp/y.txt
aws --profile storin-reader s3api list-objects-v2 --bucket <BUCKET>
# Devem retornar 403 (AccessDenied)
aws --profile storin-reader s3api put-object --bucket <BUCKET> --key ot.txt --body /tmp/t.txt
aws --profile storin-reader s3api delete-object --bucket <BUCKET> --key wr.txt
Resultado esperado
| Identidade | PUT | GET | LIST | DELETE |
|---|---|---|---|---|
| Owner | ✅ | ✅ | ✅ | ✅ |
| Writer | ✅ | ❌ | ❌ | ❌ |
| Reader | ❌ | ✅ | ✅ | ❌ |
🛠️ Troubleshooting – Problemas Comuns
❌ 403 AccessDenied ao aplicar ou usar a policy
- Verifique se o
Principalestá no formato"CanonicalUser": "<USER_ID>". - Confirme se o User ID copiado é do projeto correto (aba Acessos).
- Confirme se a policy foi aplicada com a credencial do dono do bucket.
❌ ValidationError em todo upload (AWS CLI)
Faltam as linhas de checksum no ~/.aws/config. Adicione ao perfil:
request_checksum_calculation = when_required
response_checksum_validation = when_required
❌ O Writer consegue ler os próprios arquivos
O bloco DenyReadForWriter não está na policy ou está com o User ID errado. Revise a policy e aplique novamente.
❌ A credencial "restrita" tem acesso total
A Access Key foi gerada no mesmo projeto do dono do bucket. Chaves do mesmo projeto compartilham o mesmo User ID. Crie um projeto separado para o perfil restrito, conforme a Parte 1.
❌ O Reader não consegue listar o bucket
A ação s3:ListBucket precisa dos dois resources: arn:aws:s3:::<BUCKET> e arn:aws:s3:::<BUCKET>/*.
O Writer pode enviar um objeto com uma chave já existente, substituindo o conteúdo anterior. Se isso for um risco no seu caso, use chaves únicas no upload (por exemplo, com data e hora no nome) ou habilite o versionamento no bucket.
📘 Documentação relacionada: Configurando a AWS CLI com o Storin