Cenário clássico para quem trabalha com cloud: uma aplicação rodando numa VM da OCI precisa ler ou escrever em um bucket do Object Storage. Pode ser um job que envia logs para arquivamento, um worker que processa os arquivos que foram enviados naquele dia ou quem sabe um script de sincronização. Todo mundo sabe o jeito mais fácil de lidar com a situação: gerar uma API key, jogar as credenciais num arquivo .env, importar com python-dotenv e resolvido.
Funciona bem, mas vamos pensar um pouco no que acontece depois disso.
Resolvido mesmo?
Aquele .env agora mora em disco. Está acessível a qualquer processo rodando com permissão suficiente naquela VM. Se a máquina for comprometida - seja um pacote vulnerável, talvez um container mal configurado ou um colaborador com mais acessos do que deveria, acaba permitindo que o atacante coloque as mãos numa credencial que vai continuar valendo até alguém perceber o que acontecer e revogá-la manualmente. E vamos ser honestos: rotacionar chave em produção dá trabalho, e por isso quase ninguém faz como deveria.
O Instance Principal resolve esse problema de uma forma bem mais elegante. Em vez de usarmos uma credencial estática criada manualmente, a própria VM passa a ter uma identidade IAM, gerenciada e rotacionada pela infraestrutura da Oracle. O código não tem mais credencial visível alguma: nenhum arquivo.env, nenhuma variável de ambiente sensível e nenhum config file com chave privada. A autenticação acontece na camada da infra, não na camada da aplicação.
Gostou da ideia? Nesse artigo vou ensinar como implementar essa solução do zero. Sem complicações, com tendo cuidado para te mostrar onde cada peça desse quebra-cabeças precisa estar.
Pré-requisitos
- Conta na OCI (Free Tier resolve).
- OCI CLI configurado - Cloud Shell já vem pronto e é o que vou usar.
- Uma instância Compute rodando Linux (estou usando Ubuntu 24.04).
1. Criando o bucket
Primeiro pegamos o OCID do compartment onde tudo vai ficar. No Cloud Shell:
oci iam compartment list --include-root \
--query "data[*].{name:name, id:id}" --output table
Com o OCID em mãos, criamos o bucket:
oci os bucket create \ --name ace-demo \ --compartment-id <seu-compartment-ocid>
2. Criando o Dynamic Group
O Dynamic Group é o que faz a ponte entre a VM e a identidade IAM. Em vez de adicionar usuários, a regra de matching identifica recursos, neste caso, a instância específica pelo OCID:
oci iam dynamic-group create \
--name ace-demo-dg \
--description "Dynamic group para Instance Principal" \
--matching-rule "ANY {instance.id = '<ocid-da-sua-instancia>'}"
Aliás, importante salientar: a regra pode ser bem mais flexível. Dá para incluir todas as instâncias de um compartment, ou filtrar por tags, por exemplo. Para um cenário real com várias VMs cumprindo a mesma função, uma tag costuma ser o caminho mais limpo.
3. Criando a Policy
A policy é onde a autorização é definida, quem pode fazer o quê e onde:
oci iam policy create \ --compartment-id <seu-compartment-ocid> \ --name ace-demo-policy \ --description "Policy para Instance Principal acessar Object Storage" \ --statements '["allow dynamic-group ace-demo-dg to manage objects in tenancy where target.bucket.name='"'"'ace-demo'"'"'"]'
Aqui o princípio do menor privilégio vale a pena ser respeitado. Eu limitei a um bucket específico via target.bucket.name. Em produção, restrinja sempre o máximo possível: quanto mais específico, melhor.

4. Instalando o SDK na VM
Dentro da instância:
sudo apt update -q sudo apt install python3-pip -y sudo pip3 install oci --break-system-packages --ignore-installed urllib3
O --ignore-installed urllib3 é necessário porque o Ubuntu 24.04 já traz uma versão do pacote via apt e o pip recusa sobrescrever sem essa flag.

5. O script "zero credenciais"

Preste atenção no código. Não há chaves API, nem config files sendo lido, nada de os.getenv("OCI_USER_OCID"). O InstancePrincipalsSecurityTokenSigner busca o token diretamente no serviço de metadata da instância, ou seja, o endpoint interno que só responde a chamadas vindas da própria VM. O token tem vida curta e é renovado automaticamente pelo SDK enquanto o processo estiver rodando.
6. Resultado
Rodando o script:

Pronto. Listagem do bucket funcionando com autenticação 100% baseada em infraestrutura.
Por que nem todo mundo faz dessa forma?
Se Instance Principal é tão bom, por que tanto código por aí ainda usa config file? Vamos lá:
- Só funciona dentro da OCI: Se sua VM está rodando em outra cloud, on-premise ou no seu notebook, Instance Principal não existe. Nesses cenários, config file ou variáveis de ambiente são mesmo o único caminho.
- O setup inicial tem várias peças: Dynamic Group, Policy, VCN, Internet Gateway, Security List... Para quem está começando na OCI, é muita coisa para assimilar. Para um script único ou que será descartado, talvez não seja a opção mais eficiente.
- O conceito é menos difundido que autenticação por chave: Quem trabalha com clouds geralmente passa primeiro pelo modelo de chave de acesso, comum em AWS e Azure. Instance Principal é específico da OCI, e leva tempo até entrar no radar.
- Lei do menor esforço: Quem já tem ambiente funcionando com config file não vai mexer em time que está ganhando sem um bom motivo. E se não tem nada explodindo, dificilmente alguém vai querer atualizar o ambiente.
Quando realmente vale a pena?
A regra que costumo seguir é direta:
- Código rodando em produção dentro de uma VM da OCI → Instance Principal.
- Código rodando em qualquer outro lugar → config file ou variável de ambiente, analisando caso a caso.
Na prática, a diferença é bem grande. Com Instance Principal, a identidade vive junto com a infra: quando a VM é destruída, a credencial desaparece junto com ela. Quando uma nova é criada via Terraform ou OCI Resource Manager, ela já nasce com a identidade certa. Ninguém precisa provisionar chaves manualmente, nem cair naquela mesma situação logo após o deploy "Xii, esqueci de configurar os acessos".
Parece o tipo de mudança que não faz muita diferença a primeira vista, mas quando seu ambiente começa a crescer, você vai entender bem rápido as vantagens.