@dooer/dooer-test-env 1.11.2 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/getting-access.md +175 -0
- package/docs/issuing-access.md +271 -0
- package/package.json +2 -1
- package/readme.md +15 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Getting access (new developer)
|
|
2
|
+
|
|
3
|
+
`dooer-test-env` reads the staging cluster to build its compose file, log in to the image registries and
|
|
4
|
+
fetch the BankID cert. That needs two things, in this order:
|
|
5
|
+
|
|
6
|
+
1. **VPN** — the cluster API is not reachable from the open internet.
|
|
7
|
+
2. **kubectl access** — a client certificate identifying you to the cluster.
|
|
8
|
+
|
|
9
|
+
**Both come from an admin**: they create your VPN tunnel and your cluster credential, and send you two
|
|
10
|
+
files — a WireGuard `.conf` and a `kubeconfig`. You install them and check they work. See
|
|
11
|
+
[issuing-access.md](./issuing-access.md) for their side.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 0. Prerequisites
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
brew install wireguard-tools kubernetes-cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`openssl` ships with macOS. Check everything is there:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
wg --version && kubectl version --client && openssl version
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. VPN
|
|
30
|
+
|
|
31
|
+
**Your admin creates the tunnel and sends you a `.conf` file.** You do not create it yourself and you do
|
|
32
|
+
not need a Robo10 token for this — ask an admin, who follows
|
|
33
|
+
[issuing-access.md § 1](./issuing-access.md#1-vpn--create-and-hand-over-a-tunnel).
|
|
34
|
+
|
|
35
|
+
The file they send you contains a **private key**. Treat it like a password: keep it out of chat, tickets
|
|
36
|
+
and git, install it, and delete the copy they sent you.
|
|
37
|
+
|
|
38
|
+
### 1a. Install the config
|
|
39
|
+
|
|
40
|
+
`wg-quick` takes the interface name from the **filename**, so the name you pick here is the name you use in
|
|
41
|
+
every later command. Check first what is already there — **do not overwrite an existing tunnel**:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
ls /opt/homebrew/etc/wireguard/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then install it (using `roboten` as the interface name):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
sudo mkdir -p /opt/homebrew/etc/wireguard
|
|
51
|
+
sudo cp ~/Downloads/<the-file-they-sent>.conf /opt/homebrew/etc/wireguard/roboten.conf
|
|
52
|
+
sudo chmod 600 /opt/homebrew/etc/wireguard/roboten.conf
|
|
53
|
+
rm ~/Downloads/<the-file-they-sent>.conf # the copy under /opt/homebrew is the one wg-quick reads
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 1b. Connect, disconnect, restart
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
sudo wg-quick up roboten # connect
|
|
60
|
+
sudo wg-quick down roboten # disconnect
|
|
61
|
+
sudo wg-quick down roboten && sudo wg-quick up roboten # restart (after a config change or sleep/wake)
|
|
62
|
+
|
|
63
|
+
sudo wg show # status: handshake time + transfer counters
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`wg-quick` is not a daemon: the tunnel does **not** survive a reboot, and after a laptop sleep it sometimes
|
|
67
|
+
needs the restart above. If `wg show` reports a `latest handshake` older than a couple of minutes while you
|
|
68
|
+
are actively using the cluster, restart it.
|
|
69
|
+
|
|
70
|
+
To start it automatically at boot:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
sudo brew services start wireguard-tools # starts wg0 by default
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
That service is hard-wired to the `wg0` interface, so it only helps if you named your file `wg0.conf`.
|
|
77
|
+
|
|
78
|
+
### 1c. Verify the VPN works
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
sudo wg show # expect a recent "latest handshake"
|
|
82
|
+
nc -vz k8s.roboten-infra.com 64430 # expect: succeeded / open
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If `nc` hangs or is refused, the tunnel is not carrying traffic — restart it (1b). Until this passes, no
|
|
86
|
+
amount of kubectl configuration will help.
|
|
87
|
+
|
|
88
|
+
> The tunnel routes the cluster network (including the API server) through WireGuard. If you already have
|
|
89
|
+
> another VPN claiming those ranges, they will fight over the routes — bring only one up at a time.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 2. kubectl access
|
|
94
|
+
|
|
95
|
+
**Your admin sends you a ready-made `kubeconfig` file.** You do not generate keys or assemble anything —
|
|
96
|
+
they create the credential and hand it over
|
|
97
|
+
([issuing-access.md § 2](./issuing-access.md#2-kubectl--create-their-credential)).
|
|
98
|
+
|
|
99
|
+
Like the VPN config, that file contains a **private key**. Same handling: install it, then delete the copy
|
|
100
|
+
they sent you.
|
|
101
|
+
|
|
102
|
+
### 2a. Install it
|
|
103
|
+
|
|
104
|
+
**If you have no other clusters** — simplest, just put it in place:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
mkdir -p ~/.kube
|
|
108
|
+
cp ~/Downloads/<yourname>.kubeconfig ~/.kube/config
|
|
109
|
+
chmod 600 ~/.kube/config
|
|
110
|
+
rm ~/Downloads/<yourname>.kubeconfig
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**If you already use kubectl for something else**, merge instead of overwriting:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
cp ~/.kube/config ~/.kube/config.backup # always back up first
|
|
117
|
+
KUBECONFIG=~/.kube/config:~/Downloads/<yourname>.kubeconfig \
|
|
118
|
+
kubectl config view --flatten > /tmp/merged && mv /tmp/merged ~/.kube/config
|
|
119
|
+
chmod 600 ~/.kube/config
|
|
120
|
+
rm ~/Downloads/<yourname>.kubeconfig
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Then select the context (the admin will tell you its name, `<firstname>-admin@kubernetes`):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
kubectl config get-contexts
|
|
127
|
+
kubectl config use-context <firstname>-admin@kubernetes
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 2b. Verify
|
|
131
|
+
|
|
132
|
+
With the VPN up:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
kubectl auth whoami
|
|
136
|
+
# Username <firstname>-admin
|
|
137
|
+
# Groups [system:authenticated]
|
|
138
|
+
|
|
139
|
+
kubectl get pods -n dooer-staging | head -3
|
|
140
|
+
kubectl get pods -n dooer-production | head -3
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Then the two checks `dooer-test-env` actually depends on:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
kubectl auth can-i get secrets -n dooer-staging # yes — registry pull secrets + BankID cert
|
|
147
|
+
kubectl get svc dooer-database -n dooer-staging # the database service the base-DB build reads
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
All of those must succeed before `dooer-test-env setup` will work.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 3. You are done
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npx @dooer/dooer-test-env@latest setup
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`setup` re-checks all of the above and tells you exactly which piece is missing if something is wrong.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Troubleshooting
|
|
165
|
+
|
|
166
|
+
| Symptom | Cause |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `dial tcp … i/o timeout` from kubectl | VPN is down — `sudo wg show`, then restart it (1b) |
|
|
169
|
+
| `nc` to the API server hangs | Tunnel is up but not carrying traffic; restart it |
|
|
170
|
+
| `error: You must be logged in to the server (Unauthorized)` | The certificate in your kubeconfig is expired or unknown to the cluster — ask for a re-issue |
|
|
171
|
+
| `Error from server (Forbidden)` | You *are* authenticated; your user has no permissions bound yet — ask the admin to complete their § 2e (bind permissions) |
|
|
172
|
+
| `wg-quick: 'roboten' already exists` | The interface is already up — `sudo wg-quick down roboten` first |
|
|
173
|
+
|
|
174
|
+
Certificates are issued for **one year**. When yours expires, ask your admin for a new kubeconfig and
|
|
175
|
+
repeat section 2 — your permissions stay in place, so they only have to re-issue the credential.
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Issuing access (admin)
|
|
2
|
+
|
|
3
|
+
The other side of [getting-access.md](./getting-access.md). Two independent things:
|
|
4
|
+
|
|
5
|
+
| | Who does it | What you do |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| **VPN tunnel** | you | create it and send them the config |
|
|
8
|
+
| **kubectl credential** | you | create the certificate, bind permissions, send a kubeconfig |
|
|
9
|
+
|
|
10
|
+
You need a Robo10 token (§1a), `kubectl` with cluster-admin (`system:masters`), and your own VPN up.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. VPN — create and hand over a tunnel
|
|
15
|
+
|
|
16
|
+
You create the tunnel and send the developer its config. They do not need a Robo10 token, which matters:
|
|
17
|
+
a brand-new joiner often has no working login yet, and the VPN API generates the keypair **server-side**
|
|
18
|
+
anyway — the config comes back with the private key in it either way, so there is no custody advantage to
|
|
19
|
+
making them do it.
|
|
20
|
+
|
|
21
|
+
### 1a. Get a Robo10 token (yours)
|
|
22
|
+
|
|
23
|
+
Opens a browser — log in with **your `@robo10.com` account**:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
TOKEN="$(go run github.com/strehle/cmdline-openid-client/openid-client@latest \
|
|
27
|
+
-issuer https://oidc-provider-backend.api.staging.roboten-dev.com \
|
|
28
|
+
-client_id ro_authentication_cl_id \
|
|
29
|
+
-port 34466 | awk '/===/ { if (start) nextfile; start = 1; next } start { print }' | jq -r .access_token)"
|
|
30
|
+
|
|
31
|
+
[ -n "$TOKEN" ] && echo "token acquired" || echo "no token — did the browser login complete?"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Needs `go` and `jq` (`brew install go jq`). Keep using **this same terminal**: `$TOKEN` lives only in this
|
|
35
|
+
shell, and everything below needs it.
|
|
36
|
+
|
|
37
|
+
<details>
|
|
38
|
+
<summary>Alternative if the Go client will not run</summary>
|
|
39
|
+
|
|
40
|
+
1. Open <https://chat.roboten.com> and log in.
|
|
41
|
+
2. DevTools → **Application** → **Storage → Cookies**.
|
|
42
|
+
3. Copy the value of the `x-op-token` cookie.
|
|
43
|
+
4. In your terminal: `TOKEN=<the-cookie-value>`
|
|
44
|
+
</details>
|
|
45
|
+
|
|
46
|
+
### 1b. Create their tunnel
|
|
47
|
+
|
|
48
|
+
Name it after the person (and their machine if they need more than one) so the list stays readable:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
NAME="Firstname Lastname"
|
|
52
|
+
curl -sS -H "Authorization: Bearer $TOKEN" \
|
|
53
|
+
-H 'Content-Type: application/json' \
|
|
54
|
+
-d "{ \"name\": \"$NAME\" }" \
|
|
55
|
+
https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The response contains the tunnel's **id**. To find it again later, list them (1d).
|
|
59
|
+
|
|
60
|
+
### 1c. Download the config and hand it over
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
ID=<the id from the previous step>
|
|
64
|
+
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
|
|
65
|
+
https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels/$ID/actions/get-config \
|
|
66
|
+
> ~/Downloads/$NAME.conf
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
> **This file contains a private key.** Send it over a channel you would send a password over — a shared
|
|
70
|
+
> vault entry or an expiring secure link — not email, Slack or a ticket. Tell them to install it and delete
|
|
71
|
+
> the copy you sent, and delete your own copy once they confirm.
|
|
72
|
+
|
|
73
|
+
Then point them at [getting-access.md § 1](./getting-access.md#1-vpn).
|
|
74
|
+
|
|
75
|
+
One tunnel per person per machine: two devices sharing one config will fight over the session, so create a
|
|
76
|
+
second tunnel rather than re-sending the first.
|
|
77
|
+
|
|
78
|
+
### 1d. List tunnels
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
curl -sS -H "Authorization: Bearer $TOKEN" https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 1e. Revoke a tunnel
|
|
85
|
+
|
|
86
|
+
`DELETE` is not in the VPN service's own docs, but it works (verified 2026-09-04 — returns `204` and the
|
|
87
|
+
tunnel disappears from the list):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
curl -sS -X DELETE -H "Authorization: Bearer $TOKEN" \
|
|
91
|
+
https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels/$ID
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
That invalidates the tunnel server-side, so it is the real off-switch for VPN access when someone leaves —
|
|
95
|
+
do it *and* revoke their kubectl permissions (§3).
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 2. kubectl — create their credential
|
|
100
|
+
|
|
101
|
+
The cluster authenticates users with **x509 client certificates** signed by the cluster CA. The username is
|
|
102
|
+
the certificate's **Common Name (CN)**; RBAC is bound to that string.
|
|
103
|
+
|
|
104
|
+
You do all of it and hand over a finished `kubeconfig`.
|
|
105
|
+
|
|
106
|
+
> Everything below was verified end to end against the live cluster (2026-09-04) with a throwaway
|
|
107
|
+
> `guidetest-admin`: the resulting kubeconfig read `dooer-production` and `dooer-staging`, including
|
|
108
|
+
> secrets. The test user was then removed.
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
USER_NAME=<firstname>-admin # becomes their cluster username
|
|
112
|
+
WORKDIR=$(mktemp -d) && cd "$WORKDIR"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Work in a temp directory — it holds their private key until you hand it over, and you delete it at the end.
|
|
116
|
+
|
|
117
|
+
### 2a. Generate their key and CSR
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
openssl genrsa -out "$USER_NAME.key" 2048
|
|
121
|
+
openssl req -new -key "$USER_NAME.key" -out "$USER_NAME.csr" -subj "/CN=$USER_NAME"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 2b. Submit it as a CertificateSigningRequest
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cat <<EOF | kubectl apply -f -
|
|
128
|
+
apiVersion: certificates.k8s.io/v1
|
|
129
|
+
kind: CertificateSigningRequest
|
|
130
|
+
metadata:
|
|
131
|
+
name: $USER_NAME
|
|
132
|
+
spec:
|
|
133
|
+
request: $(base64 -i "$USER_NAME.csr" | tr -d '\n')
|
|
134
|
+
signerName: kubernetes.io/kube-apiserver-client
|
|
135
|
+
expirationSeconds: 31536000 # 1 year
|
|
136
|
+
usages:
|
|
137
|
+
- client auth
|
|
138
|
+
EOF
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
If the name already exists (a renewal), delete the old object first:
|
|
142
|
+
`kubectl delete csr "$USER_NAME" --ignore-not-found`.
|
|
143
|
+
|
|
144
|
+
### 2c. Approve and extract the certificate
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
kubectl certificate approve "$USER_NAME"
|
|
148
|
+
|
|
149
|
+
kubectl get csr "$USER_NAME" -o jsonpath='{.status.certificate}' | base64 -d > "$USER_NAME.crt"
|
|
150
|
+
openssl x509 -in "$USER_NAME.crt" -noout -subject -issuer -dates
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Expect `subject=CN=<firstname>-admin`, `issuer=CN=kubernetes`, and a one-year window.
|
|
154
|
+
|
|
155
|
+
If `.status.certificate` is empty the signer has not run yet — wait a couple of seconds and repeat. If it
|
|
156
|
+
stays empty, check `kubectl describe csr "$USER_NAME"`.
|
|
157
|
+
|
|
158
|
+
### 2d. Extract the cluster CA
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 2e. Bind permissions
|
|
165
|
+
|
|
166
|
+
This is what makes the certificate useful — without it they authenticate but can do nothing. These are the
|
|
167
|
+
same five ClusterRoles the existing admins (`jimmy-admin`, `sam-admin`, `trajko-admin`) hold:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
for r in admin gateway-creator namespace-service-role clusterissuer-admin network-admin; do
|
|
171
|
+
kubectl create clusterrolebinding "${r}-user-${USER_NAME}" --clusterrole="$r" --user="$USER_NAME"
|
|
172
|
+
done
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| ClusterRole | Grants |
|
|
176
|
+
| --- | --- |
|
|
177
|
+
| `admin` | full read/write inside namespaces (the built-in Kubernetes role) |
|
|
178
|
+
| `gateway-creator` | Gateway API resources |
|
|
179
|
+
| `namespace-service-role` | namespace-scoped service management |
|
|
180
|
+
| `clusterissuer-admin` | cert-manager ClusterIssuers (cluster-scoped) |
|
|
181
|
+
| `network-admin` | NetworkAttachmentDefinitions (Multus), cluster-wide |
|
|
182
|
+
|
|
183
|
+
The declarative equivalent lives in
|
|
184
|
+
`rosopr7102-roboten-hosting-services/clusterrole-admin.yaml`. Creating the bindings with `kubectl` as above
|
|
185
|
+
is enough for the cluster, but that file is the record of who has access — **add the new user there and
|
|
186
|
+
commit it**, or the next person reading it will get a false picture.
|
|
187
|
+
|
|
188
|
+
On a renewal, skip this step: the bindings are attached to the username, not to the certificate.
|
|
189
|
+
|
|
190
|
+
### 2f. Assemble the kubeconfig
|
|
191
|
+
|
|
192
|
+
`--embed-certs=true` inlines the key and certificates, so the file you hand over is self-contained:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
SERVER=https://k8s.roboten-infra.com:64430
|
|
196
|
+
KC="$WORKDIR/$USER_NAME.kubeconfig"
|
|
197
|
+
|
|
198
|
+
KUBECONFIG="$KC" kubectl config set-cluster kubernetes \
|
|
199
|
+
--server="$SERVER" --certificate-authority=ca.crt --embed-certs=true
|
|
200
|
+
|
|
201
|
+
KUBECONFIG="$KC" kubectl config set-credentials "$USER_NAME" \
|
|
202
|
+
--client-certificate="$USER_NAME.crt" --client-key="$USER_NAME.key" --embed-certs=true
|
|
203
|
+
|
|
204
|
+
KUBECONFIG="$KC" kubectl config set-context "$USER_NAME@kubernetes" \
|
|
205
|
+
--cluster=kubernetes --user="$USER_NAME"
|
|
206
|
+
|
|
207
|
+
KUBECONFIG="$KC" kubectl config use-context "$USER_NAME@kubernetes"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 2g. Verify it before handing it over
|
|
211
|
+
|
|
212
|
+
Test the actual file, not just the RBAC — with your own VPN up:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
KUBECONFIG="$KC" kubectl auth whoami # Username: <firstname>-admin
|
|
216
|
+
KUBECONFIG="$KC" kubectl get pods -n dooer-staging | head -3
|
|
217
|
+
KUBECONFIG="$KC" kubectl get pods -n dooer-production | head -3
|
|
218
|
+
KUBECONFIG="$KC" kubectl auth can-i get secrets -n dooer-staging # yes
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
If `whoami` works but the reads say `Forbidden`, step 2e did not take.
|
|
222
|
+
|
|
223
|
+
### 2h. Hand it over, then clean up
|
|
224
|
+
|
|
225
|
+
> **The kubeconfig contains their private key.** Send it the same way as the VPN config — a shared vault
|
|
226
|
+
> entry or an expiring secure link, never email, Slack or a ticket.
|
|
227
|
+
|
|
228
|
+
Tell them the context name (`<firstname>-admin@kubernetes`) and point them at
|
|
229
|
+
[getting-access.md § 2](./getting-access.md#2-kubectl-access).
|
|
230
|
+
|
|
231
|
+
Once they confirm it works, destroy your copy — you are holding their key until you do:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
rm -rf "$WORKDIR"
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 3. Revoking access
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
for r in admin gateway-creator namespace-service-role clusterissuer-admin network-admin; do
|
|
243
|
+
kubectl delete clusterrolebinding "${r}-user-${USER_NAME}"
|
|
244
|
+
done
|
|
245
|
+
kubectl delete csr "$USER_NAME" # tidiness only; the CSR object is just a record
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Also remove them from `clusterrole-admin.yaml` and commit.
|
|
249
|
+
|
|
250
|
+
> **A signed certificate cannot be revoked.** Kubernetes has no CRL or OCSP: until it expires, that
|
|
251
|
+
> certificate still *authenticates* — deleting the bindings only removes what it is *allowed to do*, which
|
|
252
|
+
> leaves the holder as an authenticated user with no permissions. That is the real control, and it is why
|
|
253
|
+
> certificates are issued for one year rather than indefinitely. If a key is actually compromised, removing
|
|
254
|
+
> the bindings is the immediate mitigation; rotating the cluster CA is the only complete one, and that
|
|
255
|
+
> invalidates **everyone's** certificate at once — do not do it without planning the re-issue for all users.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Renewals
|
|
260
|
+
|
|
261
|
+
A certificate expiring is routine. Repeat **§2a–2d and 2f–2h** and send them a fresh kubeconfig; they
|
|
262
|
+
re-run [getting-access.md § 2](./getting-access.md#2-kubectl-access).
|
|
263
|
+
|
|
264
|
+
Skip **2e** — ClusterRoleBindings are bound to the username, not to the certificate, so they survive a
|
|
265
|
+
re-issue untouched.
|
|
266
|
+
|
|
267
|
+
Delete the old CSR object first, or the new one collides on the name:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
kubectl delete csr "$USER_NAME" --ignore-not-found
|
|
271
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dooer/dooer-test-env",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Run the whole Dooer backend locally (staging DB minus customers), copy/purge customers between environments, and shred — one CLI.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": "Dooer/cli-dooer-test-env",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"bin/",
|
|
15
15
|
"lib/",
|
|
16
|
+
"docs/",
|
|
16
17
|
"local-postgres/",
|
|
17
18
|
"discovery-router/"
|
|
18
19
|
],
|
package/readme.md
CHANGED
|
@@ -12,11 +12,23 @@ See **[ENVIRONMENT-PLAN.md](./ENVIRONMENT-PLAN.md)** for the full design and rat
|
|
|
12
12
|
npx @dooer/dooer-test-env <command>
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## First time here?
|
|
16
|
+
|
|
17
|
+
`setup` needs **VPN access** and a **kubectl credential** for the cluster — the compose file, the registry
|
|
18
|
+
logins and the BankID cert all come from there.
|
|
19
|
+
|
|
20
|
+
- **[Getting access](./docs/getting-access.md)** — new developer: set up the VPN, get your kubectl
|
|
21
|
+
certificate, and verify both actually work.
|
|
22
|
+
- **[Issuing access](./docs/issuing-access.md)** — admin: sign someone's certificate, bind their
|
|
23
|
+
permissions, and revoke them again.
|
|
24
|
+
|
|
25
|
+
Already have both? Straight to the quick start.
|
|
26
|
+
|
|
15
27
|
## Quick start
|
|
16
28
|
|
|
17
29
|
```bash
|
|
18
30
|
# 1. One-time: prereq checks, registry login, compose generation, BankID cert → keychain.
|
|
19
|
-
# Needs the VPN + kubectl access to dooer-staging.
|
|
31
|
+
# Needs the VPN + kubectl access to dooer-staging (see "First time here?" above).
|
|
20
32
|
npx @dooer/dooer-test-env setup
|
|
21
33
|
|
|
22
34
|
# 2. Bring the whole stack up (all staging services + frontends)
|
|
@@ -272,3 +284,5 @@ Inbound *input* validation always runs — this only affects response validation
|
|
|
272
284
|
## Prerequisites
|
|
273
285
|
|
|
274
286
|
Docker (Desktop), `kubectl` with access to the `dooer-staging` namespace (VPN), and Node 18+.
|
|
287
|
+
|
|
288
|
+
Don't have the VPN or a kubectl credential yet? → **[Getting access](./docs/getting-access.md)**.
|