defmodule Mix.Tasks.Gitgud.Registry.Keygen do
@shortdoc "Generate the RS256 keypair the OCI registry auth flow needs."
@moduledoc """
mix gitgud.registry.keygen [--out-priv PATH] [--out-pub PATH] [--bits N]
Generates the RSA keypair used by `GitGud.Packages.Token` to sign
bearer tokens for the OCI distribution flow. The private half goes
into `elixir-args.gitgud_registry_private_key` (the Phoenix app
reads it via `GITGUD_REGISTRY_PRIVATE_KEY`); the public half goes
into `zot.registry-pub.pem` (mounted at `/etc/zot/registry-pub.pem`
inside the zot pod — see `zot.yml`).
By default both PEMs are printed to stdout with delimiters. Pass
`--out-priv` and/or `--out-pub` to write to files instead.
mix gitgud.registry.keygen
mix gitgud.registry.keygen --out-priv registry-priv.pem --out-pub registry-pub.pem
mix gitgud.registry.keygen --bits 2048 # default is 4096
"""
use Mix.Task
@switches [out_priv: :string, out_pub: :string, bits: :integer]
@impl Mix.Task
def run(argv) do
{opts, _, _} = OptionParser.parse(argv, switches: @switches)
bits = Keyword.get(opts, :bits, 4096)
Application.ensure_all_started(:crypto)
Application.ensure_all_started(:public_key)
{priv_pem, pub_pem} = GitGud.Packages.Token.generate_keypair(bits)
emit(opts[:out_priv], "private", priv_pem)
emit(opts[:out_pub], "public", pub_pem)
Mix.shell().info("""
── Next steps ──────────────────────────────────────────────────
1) Put the PRIVATE PEM into the `elixir-args` Secret under key
`gitgud_registry_private_key`. With kubectl:
kubectl -n git-gud create secret generic elixir-args \\
--from-file=gitgud_registry_private_key=registry-priv.pem \\
--dry-run=client -o yaml | kubectl apply -f -
Then add this env entry to app.yml's container spec (next to
SECRET_KEY_BASE etc.):
- name: GITGUD_REGISTRY_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: elixir-args
key: gitgud_registry_private_key
2) Put the PUBLIC PEM into the `zot` Secret under key
`registry-pub.pem`:
kubectl -n git-gud create secret generic zot \\
--from-file=registry-pub.pem=registry-pub.pem \\
--dry-run=client -o yaml | kubectl apply -f -
(or paste it into the `registry-pub.pem` stringData field in
zot.yml if you don't use kubectl-apply for secrets.)
3) Restart both Deployments so they pick up the new key material:
kubectl -n git-gud rollout restart deployment/git-gud
kubectl -n git-gud rollout restart deployment/zot
Rotate by re-running this task and repeating steps 1–3. The two
halves must always come from the same generation — a `kid`
mismatch causes 401s with `invalid signature`.
""")
end
defp emit(nil, label, pem) do
Mix.shell().info("""
── #{String.upcase(label)} KEY ─────────────────────────────────
#{String.trim_trailing(pem)}
""")
end
defp emit(path, label, pem) do
File.write!(path, pem)
File.chmod!(path, if(label == "private", do: 0o600, else: 0o644))
Mix.shell().info("Wrote #{label} key to #{path} (mode #{if label == "private", do: "0600", else: "0644"})")
end
end
3.4 KiB · text
5af55d9