launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #30341
[Merge] ~cjwatson/lp-signing:charm-action-register-client into lp-signing:master
Colin Watson has proposed merging ~cjwatson/lp-signing:charm-action-register-client into lp-signing:master.
Commit message:
charm: Add a register-client action
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/lp-signing/+git/lp-signing/+merge/448278
Registering a new client with the signing service currently involves manually running a couple of undocumented commands. Package these up as an action.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/lp-signing:charm-action-register-client into lp-signing:master.
diff --git a/charm/lp-signing/README.md b/charm/lp-signing/README.md
index 03d5325..36ccca6 100644
--- a/charm/lp-signing/README.md
+++ b/charm/lp-signing/README.md
@@ -9,3 +9,10 @@ lp-signing/leader -- /srv/lp-signing/code/env/bin/lp-signing
generate-key-pair` to do this; the private halves should be stored in each
of `juju config lp-signing service_private_keys` and `juju config lp-signing
key_storage_private_keys`, each of which is a JSON-encoded list of strings.
+
+To register a new client, run:
+
+ juju run-action --wait lp-signing/leader register-client name=<client name>
+
+This will return the new private and public keys; you will need to configure
+the client service with these.
diff --git a/charm/lp-signing/actions.yaml b/charm/lp-signing/actions.yaml
new file mode 100644
index 0000000..f841a39
--- /dev/null
+++ b/charm/lp-signing/actions.yaml
@@ -0,0 +1,14 @@
+register-client:
+ description: >
+ Generate a key pair and use it to register a new client with the signing
+ service. This returns the new private and public key, which should be
+ used to configure the client.
+ params:
+ name:
+ type: string
+ description: >
+ The name of the client. This should typically be an identifier for
+ the client's role, rather than something like a hostname which might
+ change when the client system is redeployed.
+ required:
+ - name
diff --git a/charm/lp-signing/actions/actions.py b/charm/lp-signing/actions/actions.py
new file mode 100755
index 0000000..7e76442
--- /dev/null
+++ b/charm/lp-signing/actions/actions.py
@@ -0,0 +1,86 @@
+#! /usr/bin/python3
+# Copyright 2023 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+import subprocess
+import sys
+import traceback
+from pathlib import Path
+from tempfile import TemporaryDirectory
+
+sys.path.append("lib")
+
+from charms.layer import basic # noqa: E402
+
+basic.bootstrap_charm_deps()
+basic.init_config_states()
+
+from charmhelpers.core import hookenv # noqa: E402
+from ols import base # noqa: E402
+
+
+def register_client():
+ params = hookenv.action_get()
+ hookenv.log("Generating key pair.")
+ script = Path(base.code_dir(), "env", "bin", "lp-signing")
+ with TemporaryDirectory() as tmp:
+ subprocess.run(["chown", f"{base.user()}:", tmp], check=True)
+ private_key_path = Path(tmp, "private")
+ public_key_path = Path(tmp, "public")
+ subprocess.run(
+ [
+ "sudo",
+ "-H",
+ "-u",
+ base.user(),
+ script,
+ "generate-key-pair",
+ "--private-key-path",
+ private_key_path,
+ "--public-key-path",
+ public_key_path,
+ ],
+ check=True,
+ )
+ with open(private_key_path) as private_key_file, open(
+ public_key_path
+ ) as public_key_file:
+ private_key = private_key_file.read().rstrip("\n")
+ public_key = public_key_file.read().rstrip("\n")
+ subprocess.run(
+ [
+ "sudo",
+ "-H",
+ "-u",
+ base.user(),
+ f"SERVICE_CONFIG={base.service_config_path()}",
+ script,
+ "register-client",
+ params["name"],
+ public_key,
+ ],
+ check=True,
+ )
+ # Yes, we include the private key in the output; the person running this
+ # action will need it to configure the calling service.
+ hookenv.action_set({"private": private_key, "public": public_key})
+
+
+def main(argv):
+ action = Path(argv[0]).name
+ try:
+ if action == "register-client":
+ register_client()
+ else:
+ hookenv.action_fail(f"Action {action} not implemented.")
+ except Exception:
+ hookenv.action_fail("Unhandled exception")
+ tb = traceback.format_exc()
+ hookenv.action_set(dict(traceback=tb))
+ hookenv.log(f"Unhandled exception in action {action}:")
+ for line in tb.splitlines():
+ hookenv.log(line)
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/charm/lp-signing/actions/register-client b/charm/lp-signing/actions/register-client
new file mode 120000
index 0000000..405a394
--- /dev/null
+++ b/charm/lp-signing/actions/register-client
@@ -0,0 +1 @@
+actions.py
\ No newline at end of file