@dooer/dooer-test-env 1.11.2 → 1.12.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 +239 -0
- package/docs/issuing-access.md +180 -0
- package/package.json +2 -1
- package/readme.md +15 -1
|
@@ -0,0 +1,239 @@
|
|
|
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
|
+
The VPN part is self-service. The kubectl part needs an admin to sign your certificate — see
|
|
10
|
+
[issuing-access.md](./issuing-access.md) for their side.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 0. Prerequisites
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
brew install wireguard-tools go jq kubernetes-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`openssl` ships with macOS. Check everything is there:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
wg --version && go version && jq --version && kubectl version --client && openssl version
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. VPN
|
|
29
|
+
|
|
30
|
+
### 1a. Get a Robo10 token
|
|
31
|
+
|
|
32
|
+
The VPN API is authenticated with a Robo10 access token. This opens a browser — **log in with your
|
|
33
|
+
`@robo10.com` email**.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
TOKEN="$(go run github.com/strehle/cmdline-openid-client/openid-client@latest \
|
|
37
|
+
-issuer https://oidc-provider-backend.api.staging.roboten-dev.com \
|
|
38
|
+
-client_id ro_authentication_cl_id \
|
|
39
|
+
-port 34466 | awk '/===/ { if (start) nextfile; start = 1; next } start { print }' | jq -r .access_token)"
|
|
40
|
+
|
|
41
|
+
[ -n "$TOKEN" ] && echo "token acquired" || echo "no token — did the browser login complete?"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Keep using **this same terminal** for the next steps: `$TOKEN` only exists in this shell.
|
|
45
|
+
|
|
46
|
+
<details>
|
|
47
|
+
<summary>Alternative if the Go client will not run</summary>
|
|
48
|
+
|
|
49
|
+
1. Open <https://chat.roboten.com> and log in.
|
|
50
|
+
2. DevTools → **Application** → **Storage → Cookies**.
|
|
51
|
+
3. Copy the value of the `x-op-token` cookie.
|
|
52
|
+
4. In your terminal: `TOKEN=<the-cookie-value>`
|
|
53
|
+
</details>
|
|
54
|
+
|
|
55
|
+
### 1b. Create your tunnel
|
|
56
|
+
|
|
57
|
+
One tunnel per person per machine. Name it after yourself so admins can tell them apart:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
NAME="$(whoami)-$(hostname -s)"
|
|
61
|
+
curl -sS -H "Authorization: Bearer $TOKEN" \
|
|
62
|
+
-H 'Content-Type: application/json' \
|
|
63
|
+
-d "{ \"name\": \"$NAME\" }" \
|
|
64
|
+
https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The response contains the tunnel's **id** — you need it next. To find it again later:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
curl -sS -H "Authorization: Bearer $TOKEN" https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 1c. Download the tunnel config
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ID=<the id from the previous step>
|
|
77
|
+
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
|
|
78
|
+
https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels/$ID/actions/get-config \
|
|
79
|
+
> ~/roboten.conf
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> This file contains your **private key**. Treat it like a password: never commit it, never paste it into
|
|
83
|
+
> chat or a ticket.
|
|
84
|
+
|
|
85
|
+
### 1d. Install it
|
|
86
|
+
|
|
87
|
+
`wg-quick` takes the interface name from the **filename**, so the name you choose here is the name you use
|
|
88
|
+
in every later command. Pick something that will not collide with a tunnel you already have:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
sudo mkdir -p /opt/homebrew/etc/wireguard
|
|
92
|
+
sudo cp ~/roboten.conf /opt/homebrew/etc/wireguard/roboten.conf
|
|
93
|
+
sudo chmod 600 /opt/homebrew/etc/wireguard/roboten.conf
|
|
94
|
+
rm ~/roboten.conf # the copy under /opt/homebrew is the one wg-quick reads
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Check first whether that name is already taken — **do not overwrite someone else's tunnel**:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
ls /opt/homebrew/etc/wireguard/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 1e. Connect, disconnect, restart
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
sudo wg-quick up roboten # connect
|
|
107
|
+
sudo wg-quick down roboten # disconnect
|
|
108
|
+
sudo wg-quick down roboten && sudo wg-quick up roboten # restart (after a config change or a sleep/wake)
|
|
109
|
+
|
|
110
|
+
sudo wg show # status: handshake time + transfer counters
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`wg-quick` is not a daemon: the tunnel does **not** survive a reboot, and after a laptop sleep it sometimes
|
|
114
|
+
needs the restart above. If `wg show` reports a `latest handshake` older than a couple of minutes while you
|
|
115
|
+
are actively using the cluster, restart it.
|
|
116
|
+
|
|
117
|
+
To start it automatically at boot:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
sudo brew services start wireguard-tools # starts wg0 by default
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
That service is hard-wired to the `wg0` interface, so it only helps if you named your file `wg0.conf`.
|
|
124
|
+
|
|
125
|
+
### 1f. Verify the VPN works
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
sudo wg show # expect a recent "latest handshake"
|
|
129
|
+
nc -vz k8s.roboten-infra.com 64430 # expect: succeeded / open
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
If `nc` hangs or is refused, the tunnel is not carrying traffic — restart it (1e). Until this passes, no
|
|
133
|
+
amount of kubectl configuration will help.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 2. kubectl access
|
|
138
|
+
|
|
139
|
+
Authentication is a **client certificate**. You generate the key and the signing request; only the request
|
|
140
|
+
leaves your machine. Your private key never does.
|
|
141
|
+
|
|
142
|
+
### 2a. Generate your key and CSR
|
|
143
|
+
|
|
144
|
+
Use `<firstname>-admin` as the name — that string becomes your username in the cluster, and it is what the
|
|
145
|
+
admin binds permissions to.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
USER_NAME=<firstname>-admin
|
|
149
|
+
mkdir -p ~/.kube/roboten && cd ~/.kube/roboten
|
|
150
|
+
|
|
151
|
+
openssl genrsa -out "$USER_NAME.key" 2048
|
|
152
|
+
openssl req -new -key "$USER_NAME.key" -out "$USER_NAME.csr" -subj "/CN=$USER_NAME"
|
|
153
|
+
chmod 600 "$USER_NAME.key"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2b. Send the CSR to an admin
|
|
157
|
+
|
|
158
|
+
Send **only** `<firstname>-admin.csr`. It is not secret — but the `.key` next to it is, and must never
|
|
159
|
+
leave your machine.
|
|
160
|
+
|
|
161
|
+
Ask them for three things back:
|
|
162
|
+
|
|
163
|
+
| | |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `<firstname>-admin.crt` | your signed certificate |
|
|
166
|
+
| `ca.crt` | the cluster CA certificate |
|
|
167
|
+
| the API server URL | currently `https://k8s.roboten-infra.com:64430` |
|
|
168
|
+
|
|
169
|
+
### 2c. Assemble your kubeconfig
|
|
170
|
+
|
|
171
|
+
Put the two `.crt` files next to your key in `~/.kube/roboten`, then:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
cd ~/.kube/roboten
|
|
175
|
+
USER_NAME=<firstname>-admin
|
|
176
|
+
SERVER=https://k8s.roboten-infra.com:64430
|
|
177
|
+
|
|
178
|
+
KUBECONFIG=~/.kube/config kubectl config set-cluster kubernetes \
|
|
179
|
+
--server="$SERVER" --certificate-authority=ca.crt --embed-certs=true
|
|
180
|
+
|
|
181
|
+
KUBECONFIG=~/.kube/config kubectl config set-credentials "$USER_NAME" \
|
|
182
|
+
--client-certificate="$USER_NAME.crt" --client-key="$USER_NAME.key" --embed-certs=true
|
|
183
|
+
|
|
184
|
+
KUBECONFIG=~/.kube/config kubectl config set-context "$USER_NAME@kubernetes" \
|
|
185
|
+
--cluster=kubernetes --user="$USER_NAME"
|
|
186
|
+
|
|
187
|
+
KUBECONFIG=~/.kube/config kubectl config use-context "$USER_NAME@kubernetes"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`--embed-certs=true` copies the certificates *into* `~/.kube/config`, so the files in `~/.kube/roboten` are
|
|
191
|
+
only a backup after this point. Keep the `.key` anyway — you need it if you ever rebuild the config.
|
|
192
|
+
|
|
193
|
+
### 2d. Verify
|
|
194
|
+
|
|
195
|
+
With the VPN up:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
kubectl auth whoami
|
|
199
|
+
# Username <firstname>-admin
|
|
200
|
+
# Groups [system:authenticated]
|
|
201
|
+
|
|
202
|
+
kubectl get pods -n dooer-staging | head -3
|
|
203
|
+
kubectl get pods -n dooer-production | head -3
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Then the two checks `dooer-test-env` actually depends on:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
kubectl auth can-i get secrets -n dooer-staging # yes — registry pull secrets + BankID cert
|
|
210
|
+
kubectl get svc dooer-database -n dooer-staging # the database service the base-DB build reads
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
All of those must succeed before `dooer-test-env setup` will work.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 3. You are done
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npx @dooer/dooer-test-env@latest setup
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
`setup` re-checks all of the above and tells you exactly which piece is missing if something is wrong.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Troubleshooting
|
|
228
|
+
|
|
229
|
+
| Symptom | Cause |
|
|
230
|
+
| --- | --- |
|
|
231
|
+
| `dial tcp … i/o timeout` from kubectl | VPN is down — `sudo wg show`, then restart it (1e) |
|
|
232
|
+
| `nc` to the API server hangs | Tunnel is up but not carrying traffic; restart it |
|
|
233
|
+
| `error: You must be logged in to the server (Unauthorized)` | Certificate is wrong/expired, or the cluster does not know that CN — back to 2b |
|
|
234
|
+
| `Error from server (Forbidden)` | You *are* authenticated; your user has no permissions bound yet — ask the admin to complete their step 3 |
|
|
235
|
+
| `no token — did the browser login complete?` | The OIDC flow did not finish; make sure you used your `@robo10.com` account |
|
|
236
|
+
| `wg-quick: 'roboten' already exists` | The interface is already up — `sudo wg-quick down roboten` first |
|
|
237
|
+
|
|
238
|
+
Certificates are issued for **one year**. When yours expires you repeat section 2 — the admin only has to
|
|
239
|
+
re-sign; your permissions (step 3 on their side) stay in place.
|
|
@@ -0,0 +1,180 @@
|
|
|
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** | self-service | make sure they have a Robo10 login; nothing to hand out |
|
|
8
|
+
| **kubectl credential** | needs you | sign their CSR and bind their permissions |
|
|
9
|
+
|
|
10
|
+
You need `kubectl` with cluster-admin (`system:masters`) and the VPN up.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. VPN — what you actually have to do
|
|
15
|
+
|
|
16
|
+
Tunnels are **self-service**: any valid Robo10 token can create one, and the config is generated on demand
|
|
17
|
+
by the VPN API. So there is no artefact for you to produce or send.
|
|
18
|
+
|
|
19
|
+
Your only job is to make sure the person can log in at <https://chat.roboten.com> with their
|
|
20
|
+
**`@robo10.com`** account — that same identity is what the token flow authenticates. If they cannot log in,
|
|
21
|
+
that is an account-provisioning issue in Robo10, not something this guide covers.
|
|
22
|
+
|
|
23
|
+
Then point them at [getting-access.md § 1](./getting-access.md#1-vpn).
|
|
24
|
+
|
|
25
|
+
**Never** create the tunnel on their behalf and send them the config: the config embeds a private key, so a
|
|
26
|
+
tunnel they generated themselves is the only one only they hold.
|
|
27
|
+
|
|
28
|
+
To see who has tunnels (with your own token, as in the dev guide):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
curl -sS -H "Authorization: Bearer $TOKEN" https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
To revoke one — `DELETE` is not in the VPN service's own docs, but it works (verified 2026-09-04, returns
|
|
35
|
+
`204` and the tunnel disappears from the list):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
curl -sS -X DELETE -H "Authorization: Bearer $TOKEN" \
|
|
39
|
+
https://vpn.api.staging.roboten-dev.com/v1/vpn-tunnels/$ID
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That invalidates the tunnel's key server-side, so it is the real off-switch for VPN access when someone
|
|
43
|
+
leaves — do it *and* revoke their kubectl permissions (§3).
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 2. kubectl — sign their certificate
|
|
48
|
+
|
|
49
|
+
The cluster authenticates users with **x509 client certificates** signed by the cluster CA. The username is
|
|
50
|
+
the certificate's **Common Name (CN)**; RBAC is bound to that string.
|
|
51
|
+
|
|
52
|
+
You never see their private key. They send you a `.csr`; you send back a `.crt`.
|
|
53
|
+
|
|
54
|
+
### 2a. Submit their CSR to the cluster
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
USER_NAME=<firstname>-admin # must match the CN in their CSR
|
|
58
|
+
CSR_FILE=~/Downloads/$USER_NAME.csr # what they sent you
|
|
59
|
+
|
|
60
|
+
cat <<EOF | kubectl apply -f -
|
|
61
|
+
apiVersion: certificates.k8s.io/v1
|
|
62
|
+
kind: CertificateSigningRequest
|
|
63
|
+
metadata:
|
|
64
|
+
name: $USER_NAME
|
|
65
|
+
spec:
|
|
66
|
+
request: $(base64 -i "$CSR_FILE" | tr -d '\n')
|
|
67
|
+
signerName: kubernetes.io/kube-apiserver-client
|
|
68
|
+
expirationSeconds: 31536000 # 1 year
|
|
69
|
+
usages:
|
|
70
|
+
- client auth
|
|
71
|
+
EOF
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Sanity-check the CN is what you expect before approving — the CN is the identity you are about to grant
|
|
75
|
+
admin to:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
openssl req -in "$CSR_FILE" -noout -subject
|
|
79
|
+
# subject=CN=<firstname>-admin
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2b. Approve and extract the certificate
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
kubectl certificate approve "$USER_NAME"
|
|
86
|
+
|
|
87
|
+
kubectl get csr "$USER_NAME" -o jsonpath='{.status.certificate}' | base64 -d > "$USER_NAME.crt"
|
|
88
|
+
openssl x509 -in "$USER_NAME.crt" -noout -subject -issuer -dates
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Expect `subject=CN=<firstname>-admin`, `issuer=CN=kubernetes`, and a one-year window.
|
|
92
|
+
|
|
93
|
+
If `.status.certificate` is empty, the signer has not run yet — wait a couple of seconds and repeat. If it
|
|
94
|
+
stays empty, the CSR was approved but not signed; check `kubectl describe csr "$USER_NAME"`.
|
|
95
|
+
|
|
96
|
+
### 2c. Extract the cluster CA
|
|
97
|
+
|
|
98
|
+
The same file for everyone:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2d. Bind permissions
|
|
105
|
+
|
|
106
|
+
This is what makes the certificate useful — without it they authenticate but can do nothing. These are the
|
|
107
|
+
same five ClusterRoles the existing admins (`jimmy-admin`, `sam-admin`, `trajko-admin`) hold:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
for r in admin gateway-creator namespace-service-role clusterissuer-admin network-admin; do
|
|
111
|
+
kubectl create clusterrolebinding "${r}-user-${USER_NAME}" --clusterrole="$r" --user="$USER_NAME"
|
|
112
|
+
done
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
| ClusterRole | Grants |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| `admin` | full read/write inside namespaces (the built-in Kubernetes role) |
|
|
118
|
+
| `gateway-creator` | Gateway API resources |
|
|
119
|
+
| `namespace-service-role` | namespace-scoped service management |
|
|
120
|
+
| `clusterissuer-admin` | cert-manager ClusterIssuers (cluster-scoped) |
|
|
121
|
+
| `network-admin` | NetworkAttachmentDefinitions (Multus), cluster-wide |
|
|
122
|
+
|
|
123
|
+
The declarative equivalent lives in
|
|
124
|
+
`rosopr7102-roboten-hosting-services/clusterrole-admin.yaml`. Creating the bindings with `kubectl` as above
|
|
125
|
+
is enough for the cluster, but that file is the record of who has access — **add the new user there and
|
|
126
|
+
commit it**, or the next person reading it will get a false picture.
|
|
127
|
+
|
|
128
|
+
### 2e. Hand back
|
|
129
|
+
|
|
130
|
+
Send them three things (none are secret — the secret half never left their machine):
|
|
131
|
+
|
|
132
|
+
1. `<firstname>-admin.crt`
|
|
133
|
+
2. `ca.crt`
|
|
134
|
+
3. the API server URL — currently `https://k8s.roboten-infra.com:64430`
|
|
135
|
+
|
|
136
|
+
Then they follow [getting-access.md § 2c](./getting-access.md#2c-assemble-your-kubeconfig).
|
|
137
|
+
|
|
138
|
+
### 2f. Verify before you tell them it is done
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
kubectl get clusterrolebinding | grep "$USER_NAME" # expect 5 rows
|
|
142
|
+
kubectl auth can-i get pods -n dooer-production --as "$USER_NAME"
|
|
143
|
+
kubectl auth can-i get secrets -n dooer-staging --as "$USER_NAME"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`--as` impersonates the user, so you are testing the real RBAC without needing their certificate.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 3. Revoking access
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
for r in admin gateway-creator namespace-service-role clusterissuer-admin network-admin; do
|
|
154
|
+
kubectl delete clusterrolebinding "${r}-user-${USER_NAME}"
|
|
155
|
+
done
|
|
156
|
+
kubectl delete csr "$USER_NAME" # tidiness only; the CSR object is just a record
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Also remove them from `clusterrole-admin.yaml` and commit.
|
|
160
|
+
|
|
161
|
+
> **A signed certificate cannot be revoked.** Kubernetes has no CRL or OCSP: until it expires, that
|
|
162
|
+
> certificate still *authenticates* — deleting the bindings only removes what it is *allowed to do*, which
|
|
163
|
+
> leaves the holder as an authenticated user with no permissions. That is the real control, and it is why
|
|
164
|
+
> certificates are issued for one year rather than indefinitely. If a key is actually compromised, removing
|
|
165
|
+
> the bindings is the immediate mitigation; rotating the cluster CA is the only complete one, and that
|
|
166
|
+
> invalidates **everyone's** certificate at once — do not do it without planning the re-issue for all users.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Renewals
|
|
171
|
+
|
|
172
|
+
A certificate expiring is routine: the user repeats [getting-access.md § 2a–2c](./getting-access.md#2a-generate-your-key-and-csr)
|
|
173
|
+
and you repeat **2a–2c and 2e** here. Skip 2d — their ClusterRoleBindings are bound to the username, not to
|
|
174
|
+
the certificate, so they survive a re-issue untouched.
|
|
175
|
+
|
|
176
|
+
Delete the old CSR object first, or the new one collides on the name:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
kubectl delete csr "$USER_NAME" --ignore-not-found
|
|
180
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dooer/dooer-test-env",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.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)**.
|