Files
unkinben b4b8915d3e
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Scaffold the bind-tsig secrets engine
A Vault/OpenBao secrets engine that manages BIND TSIG keys via the
bind-operator companion API (Vault -> HTTP API -> BindTSIGKey CRs).

- backend + cmd entry point (plugin.ServeMultiplex), modelled on
  vault-plugin-secrets-litellm
- config path: companion API url/token/tls + defaults
- static-roles/static-creds: stable named key with managed rotation
- roles/creds: dynamic, lease-bound keys (revoke deletes the CR)
- tsig_key secret type with revoke/renew
- HTTP client for the companion API contract (/v1/keys CRUD + rotate)
- Makefile, Woodpecker CI (pre-commit/build/test + tag release RPMs),
  nfpm packaging (vault + openbao flavours)
- e2e: mock companion API + Vault + OpenBao in docker-compose, full
  lifecycle per engine; unit tests for the dynamic + static flows
2026-07-15 21:29:33 +10:00

62 lines
1.7 KiB
Go

package bindtsig
import (
"context"
"errors"
"fmt"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
const tsigKeyType = "tsig_key"
func (b *bindTSIGBackend) tsigKeySecret() *framework.Secret {
return &framework.Secret{
Type: tsigKeyType,
Fields: map[string]*framework.FieldSchema{
"name": {
Type: framework.TypeString,
Description: "The BindTSIGKey resource name.",
},
"key_name": {
Type: framework.TypeString,
Description: "The TSIG key name used in named.conf.",
},
"secret": {
Type: framework.TypeString,
Description: "The base64-encoded TSIG key material.",
},
},
Revoke: b.secretRevoke,
Renew: b.secretRenew,
}
}
// secretRevoke deletes the dynamic key (and its BindTSIGKey CR) via the API.
func (b *bindTSIGBackend) secretRevoke(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) {
rawName, ok := req.Secret.InternalData["name"]
if !ok {
return nil, errors.New("secret is missing internal name data")
}
name, ok := rawName.(string)
if !ok {
return nil, errors.New("secret internal name data is not a string")
}
client, err := b.getClient(ctx, req.Storage)
if err != nil {
return nil, err
}
if err := client.DeleteKey(ctx, name); err != nil {
return nil, fmt.Errorf("revoking tsig key %q: %w", name, err)
}
return nil, nil
}
// secretRenew extends the Vault lease. The key material is unchanged; the
// authoritative lifetime is the Vault lease.
func (b *bindTSIGBackend) secretRenew(_ context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) {
return &logical.Response{Secret: req.Secret}, nil
}