Pular para o conteúdo

Cofre de segredos

Cifrar por envelope, rotacionar a chave sem reescrever os dados, e recusar o dado adulterado.

Uma chave que nunca é trocada é uma chave que um dia vaza e continua valendo. O motivo de ninguém trocar é sempre o mesmo: trocá-la tornaria ilegível tudo que ela cifrou. O envelope resolve — os dados são cifrados por uma chave própria, e só essa chave pequena é cifrada pela mestra.

PeçaO que ela exercita
Ch.cofreas chaves com propósito e prazo
envelopar / desenveloparDEK por dado, KEK mestra
rotacionara chave nova, mantendo as antigas
recifrartrocar a mestra sem tocar nos dados

Estrutura#

text
cofre/
  src/
    cofre.df       abrir, guardar, ler
    rotacao.df     o job mensal
  tests/
forge.toml
[project]
name = "cofre"
version = "0.1.0"
description = "Cofre de segredos"
entry = "src/main.df"
dataforge = ">=1.1"

[dependencies]

[scripts]
start = "run src/main.df"
test = "test tests/"

O núcleo#

Este bloco roda sozinho — copie para um arquivo e rode dataforge run. Ele termina com assert, e é assim que esta página é conferida a cada build.

src/cofre.df
adopt Arcane.Chaves as Ch
adopt Arcane.Bytes as Bytes

cofre := Ch.cofre()
cofre.gerar("mestra", proposito := "cifrar")

segredos := {}
action guardar(nome, valor):
    segredos[nome] := cofre.envelopar(valor, "mestra")

// O envelope guarda BYTES: um segredo pode ser um certificado binario.
// Quem sabe que ali mora texto converte na saida.
action ler(nome):
    yield Bytes.para_texto(cofre.desenvelopar(segredos[nome]))

guardar("banco", "postgres://app:s3nh4@db/loja")
guardar("stripe", "chave-de-teste-ficticia")

// A rotacao: a chave nova passa a cifrar, a antiga continua abrindo.
nova := cofre.rotacionar("mestra", "cifrar")
assert ler("banco") is "postgres://app:s3nh4@db/loja"

// E o job de rotacao recifra so as DEKs — os dados ficam onde estao.
cycle nome in segredos.keys():
    segredos[nome] := cofre.recifrar(segredos[nome], "mestra")
assert segredos["banco"]["kid"] is nova.kid
out "rotacionado; o passado continua legivel"

O teste#

No projeto, a regra mora em src/ e o teste a importa pelo caminho relativo — dataforge test tests/ descobre o arquivo sozinho.

tests/nucleo_test.df
adopt ../src/cofre as C

crucible "cofre":
    trial "o que se guarda volta igual":
        C.guardar("x", "valor")
        expect C.ler("x") is "valor"

As decisões#

DecisãoSem ela
envelope (DEK/KEK)trocar a mestra é reescrever cada segredo
o kid dentro do envelopecom cinco chaves, não se sabe qual abre o quê
a chave tem propósitoa chave que assina token também decifra backup
a integridade é barulhentao dado adulterado abre como void e o programa grava nada onde havia um valor

Para ir além#

Volte para todos os tipos de projeto.