Merge ~cjwatson/lp-signing:charm-action-register-client into lp-signing:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 8ea77d8c77c4f1b0ced489e765a67b215435c90a
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/lp-signing:charm-action-register-client
Merge into: lp-signing:master
Diff against target: 135 lines (+108/-0)
4 files modified
charm/lp-signing/README.md (+7/-0)
charm/lp-signing/actions.yaml (+14/-0)
charm/lp-signing/actions/actions.py (+86/-0)
charm/lp-signing/actions/register-client (+1/-0)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+448278@code.launchpad.net

Commit message

charm: Add a register-client action

Description of the change

Registering a new client with the signing service currently involves manually running a couple of undocumented commands. Package these up as an action.

To post a comment you must log in.
Revision history for this message
Guruprasad (lgp171188) wrote :

LGTM 👍

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/charm/lp-signing/README.md b/charm/lp-signing/README.md
2index 03d5325..36ccca6 100644
3--- a/charm/lp-signing/README.md
4+++ b/charm/lp-signing/README.md
5@@ -9,3 +9,10 @@ lp-signing/leader -- /srv/lp-signing/code/env/bin/lp-signing
6 generate-key-pair` to do this; the private halves should be stored in each
7 of `juju config lp-signing service_private_keys` and `juju config lp-signing
8 key_storage_private_keys`, each of which is a JSON-encoded list of strings.
9+
10+To register a new client, run:
11+
12+ juju run-action --wait lp-signing/leader register-client name=<client name>
13+
14+This will return the new private and public keys; you will need to configure
15+the client service with these.
16diff --git a/charm/lp-signing/actions.yaml b/charm/lp-signing/actions.yaml
17new file mode 100644
18index 0000000..f841a39
19--- /dev/null
20+++ b/charm/lp-signing/actions.yaml
21@@ -0,0 +1,14 @@
22+register-client:
23+ description: >
24+ Generate a key pair and use it to register a new client with the signing
25+ service. This returns the new private and public key, which should be
26+ used to configure the client.
27+ params:
28+ name:
29+ type: string
30+ description: >
31+ The name of the client. This should typically be an identifier for
32+ the client's role, rather than something like a hostname which might
33+ change when the client system is redeployed.
34+ required:
35+ - name
36diff --git a/charm/lp-signing/actions/actions.py b/charm/lp-signing/actions/actions.py
37new file mode 100755
38index 0000000..7e76442
39--- /dev/null
40+++ b/charm/lp-signing/actions/actions.py
41@@ -0,0 +1,86 @@
42+#! /usr/bin/python3
43+# Copyright 2023 Canonical Ltd. This software is licensed under the
44+# GNU Affero General Public License version 3 (see the file LICENSE).
45+
46+import subprocess
47+import sys
48+import traceback
49+from pathlib import Path
50+from tempfile import TemporaryDirectory
51+
52+sys.path.append("lib")
53+
54+from charms.layer import basic # noqa: E402
55+
56+basic.bootstrap_charm_deps()
57+basic.init_config_states()
58+
59+from charmhelpers.core import hookenv # noqa: E402
60+from ols import base # noqa: E402
61+
62+
63+def register_client():
64+ params = hookenv.action_get()
65+ hookenv.log("Generating key pair.")
66+ script = Path(base.code_dir(), "env", "bin", "lp-signing")
67+ with TemporaryDirectory() as tmp:
68+ subprocess.run(["chown", f"{base.user()}:", tmp], check=True)
69+ private_key_path = Path(tmp, "private")
70+ public_key_path = Path(tmp, "public")
71+ subprocess.run(
72+ [
73+ "sudo",
74+ "-H",
75+ "-u",
76+ base.user(),
77+ script,
78+ "generate-key-pair",
79+ "--private-key-path",
80+ private_key_path,
81+ "--public-key-path",
82+ public_key_path,
83+ ],
84+ check=True,
85+ )
86+ with open(private_key_path) as private_key_file, open(
87+ public_key_path
88+ ) as public_key_file:
89+ private_key = private_key_file.read().rstrip("\n")
90+ public_key = public_key_file.read().rstrip("\n")
91+ subprocess.run(
92+ [
93+ "sudo",
94+ "-H",
95+ "-u",
96+ base.user(),
97+ f"SERVICE_CONFIG={base.service_config_path()}",
98+ script,
99+ "register-client",
100+ params["name"],
101+ public_key,
102+ ],
103+ check=True,
104+ )
105+ # Yes, we include the private key in the output; the person running this
106+ # action will need it to configure the calling service.
107+ hookenv.action_set({"private": private_key, "public": public_key})
108+
109+
110+def main(argv):
111+ action = Path(argv[0]).name
112+ try:
113+ if action == "register-client":
114+ register_client()
115+ else:
116+ hookenv.action_fail(f"Action {action} not implemented.")
117+ except Exception:
118+ hookenv.action_fail("Unhandled exception")
119+ tb = traceback.format_exc()
120+ hookenv.action_set(dict(traceback=tb))
121+ hookenv.log(f"Unhandled exception in action {action}:")
122+ for line in tb.splitlines():
123+ hookenv.log(line)
124+
125+
126+if __name__ == "__main__":
127+ main(sys.argv)
128diff --git a/charm/lp-signing/actions/register-client b/charm/lp-signing/actions/register-client
129new file mode 120000
130index 0000000..405a394
131--- /dev/null
132+++ b/charm/lp-signing/actions/register-client
133@@ -0,0 +1 @@
134+actions.py
135\ No newline at end of file

Subscribers

People subscribed via source and target branches