Skip to content

Commit 5d4b83d

Browse files
committed
feat(helm): support external artifact sourcing
1 parent 3ad607e commit 5d4b83d

10 files changed

Lines changed: 363 additions & 5 deletions

File tree

README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,96 @@ Generate node identities, configure consensus, and emit a Besu genesis.
66

77
The helm chart to run this on Kubernetes / OpenShift can be found [here](./charts/network-bootstrapper/README.md)
88

9+
### Deployment modes
10+
11+
Two deployment paths are supported: fully auto-generated artefacts or supplying your own genesis/static peers while sourcing node keys from an external secret store such as Conjur.
12+
13+
#### Auto-generated artefacts (bootstrapper job)
14+
15+
```bash
16+
cat <<'EOF' > values-generated.yaml
17+
network-bootstrapper:
18+
artifacts:
19+
source: generated
20+
settings:
21+
validators: 4
22+
23+
network-nodes:
24+
global:
25+
validatorReplicaCount: 4
26+
EOF
27+
28+
helm upgrade --install besu-network ./charts/network \
29+
--namespace besu \
30+
--create-namespace \
31+
--values values-generated.yaml
32+
```
33+
34+
The bootstrapper Job generates the genesis file, static-nodes list, validator keys, and faucet account and publishes them as ConfigMaps/Secrets consumed by the Besu StatefulSets.
35+
36+
#### External genesis/static peers with Conjur-managed keys
37+
38+
Genesis and static peer data can be committed to version control while validator and faucet private keys are injected at deployment time. The chart expects the validator count in `artifacts.external.validators` to match `global.validatorReplicaCount`.
39+
40+
Create a Summon manifest describing the Conjur variables and a templated values file that references the injected environment variables:
41+
42+
```bash
43+
cat <<'EOF' > conjur.env.yml
44+
BESU_NODE_VALIDATOR_0_PRIVATE_KEY: !var production/besu/validator0/private-key
45+
BESU_NODE_VALIDATOR_1_PRIVATE_KEY: !var production/besu/validator1/private-key
46+
BESU_FAUCET_PRIVATE_KEY: !var production/besu/faucet/private-key
47+
EOF
48+
49+
cat <<'EOF' > values-external.tpl.yaml
50+
network-bootstrapper:
51+
artifacts:
52+
source: external
53+
external:
54+
genesis:
55+
config:
56+
chainId: 12345
57+
alloc:
58+
"0xfund":
59+
balance: "0x56bc75e2d63100000"
60+
extraData: "0x"
61+
staticNodes:
62+
- enode://node1@validator-0.besu.svc.cluster.local:30303
63+
- enode://node2@validator-1.besu.svc.cluster.local:30303
64+
validators:
65+
- address: "0x111"
66+
publicKey: "0x222"
67+
privateKey: "${BESU_NODE_VALIDATOR_0_PRIVATE_KEY}"
68+
enode: enode://validator1@validator-0.besu.svc.cluster.local:30303
69+
- address: "0x333"
70+
publicKey: "0x444"
71+
privateKey: "${BESU_NODE_VALIDATOR_1_PRIVATE_KEY}"
72+
enode: enode://validator2@validator-1.besu.svc.cluster.local:30303
73+
faucet:
74+
address: "0xfaucet"
75+
publicKey: "0xfaucetpub"
76+
privateKey: "${BESU_FAUCET_PRIVATE_KEY}"
77+
78+
global:
79+
validatorReplicaCount: 2
80+
81+
network-nodes:
82+
validatorReplicaCount:
83+
global:
84+
validatorReplicaCount: 2
85+
EOF
86+
87+
summon -f conjur.env.yml envsubst < values-external.tpl.yaml > values-external.yaml
88+
89+
helm upgrade --install besu-network ./charts/network \
90+
--namespace besu \
91+
--create-namespace \
92+
--values values-external.yaml
93+
94+
rm values-external.yaml
95+
```
96+
97+
Summon resolves the secrets in memory, `envsubst` renders them into a transient values file, and Helm creates the ConfigMaps/Secrets required by the Besu nodes. The temporary file is removed once the release is installed.
98+
999
## CLI usage
10100

11101
```

README.tpl

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,94 @@ Generate node identities, configure consensus, and emit a Besu genesis.
66

77
The helm chart to run this on Kubernetes / OpenShift can be found [here](./charts/network-bootstrapper/README.md)
88

9+
### Deployment modes
10+
11+
Two deployment paths are supported: fully auto-generated artefacts or supplying your own genesis/static peers while sourcing node keys from an external secret store such as Conjur.
12+
13+
#### Auto-generated artefacts (bootstrapper job)
14+
15+
```bash
16+
cat <<'EOF' > values-generated.yaml
17+
network-bootstrapper:
18+
artifacts:
19+
source: generated
20+
settings:
21+
validators: 4
22+
23+
network-nodes:
24+
global:
25+
validatorReplicaCount: 4
26+
EOF
27+
28+
helm upgrade --install besu-network ./charts/network \
29+
--namespace besu \
30+
--create-namespace \
31+
--values values-generated.yaml
32+
```
33+
34+
The bootstrapper Job generates the genesis file, static-nodes list, validator keys, and faucet account and publishes them as ConfigMaps/Secrets consumed by the Besu StatefulSets.
35+
36+
#### External genesis/static peers with Conjur-managed keys
37+
38+
Genesis and static peer data can be committed to version control while validator and faucet private keys are injected at deployment time. The chart expects the validator count in `artifacts.external.validators` to match `global.validatorReplicaCount`.
39+
40+
Create a Summon manifest describing the Conjur variables and a templated values file that references the injected environment variables:
41+
42+
```bash
43+
cat <<'EOF' > conjur.env.yml
44+
BESU_NODE_VALIDATOR_0_PRIVATE_KEY: !var production/besu/validator0/private-key
45+
BESU_NODE_VALIDATOR_1_PRIVATE_KEY: !var production/besu/validator1/private-key
46+
BESU_FAUCET_PRIVATE_KEY: !var production/besu/faucet/private-key
47+
EOF
48+
49+
cat <<'EOF' > values-external.tpl.yaml
50+
network-bootstrapper:
51+
artifacts:
52+
source: external
53+
external:
54+
genesis:
55+
config:
56+
chainId: 12345
57+
alloc:
58+
"0xfund":
59+
balance: "0x56bc75e2d63100000"
60+
extraData: "0x"
61+
staticNodes:
62+
- enode://node1@validator-0.besu.svc.cluster.local:30303
63+
- enode://node2@validator-1.besu.svc.cluster.local:30303
64+
validators:
65+
- address: "0x111"
66+
publicKey: "0x222"
67+
privateKey: "${BESU_NODE_VALIDATOR_0_PRIVATE_KEY}"
68+
enode: enode://validator1@validator-0.besu.svc.cluster.local:30303
69+
- address: "0x333"
70+
publicKey: "0x444"
71+
privateKey: "${BESU_NODE_VALIDATOR_1_PRIVATE_KEY}"
72+
enode: enode://validator2@validator-1.besu.svc.cluster.local:30303
73+
faucet:
74+
address: "0xfaucet"
75+
publicKey: "0xfaucetpub"
76+
privateKey: "${BESU_FAUCET_PRIVATE_KEY}"
77+
78+
global:
79+
validatorReplicaCount: 2
80+
81+
network-nodes:
82+
validatorReplicaCount:
83+
global:
84+
validatorReplicaCount: 2
85+
EOF
86+
87+
summon -f conjur.env.yml envsubst < values-external.tpl.yaml > values-external.yaml
88+
89+
helm upgrade --install besu-network ./charts/network \
90+
--namespace besu \
91+
--create-namespace \
92+
--values values-external.yaml
93+
94+
rm values-external.yaml
95+
```
96+
97+
Summon resolves the secrets in memory, `envsubst` renders them into a transient values file, and Helm creates the ConfigMaps/Secrets required by the Besu nodes. The temporary file is removed once the release is installed.
98+
999
## CLI usage

charts/network/charts/network-bootstrapper/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ A Helm chart for Kubernetes
1515
| Key | Type | Default | Description |
1616
|-----|------|---------|-------------|
1717
| affinity | object | `{}` | |
18+
| artifacts.external.faucet.address | string | `""` | Faucet account address stored in the `besu-faucet-address` ConfigMap when `source` equals `external`. |
19+
| artifacts.external.faucet.privateKey | string | `""` | Faucet private key stored in the `besu-faucet-private-key` Secret when `source` equals `external`. |
20+
| artifacts.external.faucet.publicKey | string | `""` | Faucet account public key stored in the `besu-faucet-pubkey` ConfigMap when `source` equals `external`. |
21+
| artifacts.external.genesis | object | `{}` | Besu genesis document rendered into the `besu-genesis` ConfigMap when `source` equals `external`. |
22+
| artifacts.external.staticNodes | list | `[]` | Collection of enode URIs persisted to the `besu-static-nodes` ConfigMap when `source` equals `external`. |
23+
| artifacts.external.validators | list | `[]` | Validator node definitions providing the data expected by the nodes chart. Each entry must include `address`, `publicKey`, `privateKey`, and `enode`. |
24+
| artifacts.source | string | `"generated"` | Determines how Besu network artifacts are populated. Use `generated` to run the job or `external` to supply values manually. |
1825
| fullnameOverride | string | `"bootstrapper"` | Override for the fully qualified resource name generated by helpers. |
1926
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy controlling when Kubernetes fetches updated image layers. |
2027
| image.repository | string | `"ghcr.io/settlemint/network-bootstrapper"` | OCI registry path hosting the network bootstrapper image. |
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
{{- $artifactSource := default "generated" .Values.artifacts.source -}}
2+
{{- if eq $artifactSource "external" }}
3+
{{- $root := . -}}
4+
{{- $external := .Values.artifacts.external | default (dict) -}}
5+
{{- $genesis := get $external "genesis" -}}
6+
{{- $staticNodes := get $external "staticNodes" -}}
7+
{{- $validators := get $external "validators" -}}
8+
{{- $faucet := get $external "faucet" -}}
9+
{{- $validatorCount := len $validators -}}
10+
{{- if not $genesis }}{{ fail "artifacts.external.genesis must be provided when artifacts.source is 'external'." }}{{- end }}
11+
{{- if not $staticNodes }}{{ fail "artifacts.external.staticNodes must include at least one enode when artifacts.source is 'external'." }}{{- end }}
12+
{{- if not $validators }}{{ fail "artifacts.external.validators must include at least one entry when artifacts.source is 'external'." }}{{- end }}
13+
{{- if not ($faucet.address) }}{{ fail "artifacts.external.faucet.address must be set when artifacts.source is 'external'." }}{{- end }}
14+
{{- if not ($faucet.publicKey) }}{{ fail "artifacts.external.faucet.publicKey must be set when artifacts.source is 'external'." }}{{- end }}
15+
{{- if not ($faucet.privateKey) }}{{ fail "artifacts.external.faucet.privateKey must be set when artifacts.source is 'external'." }}{{- end }}
16+
{{- $globalValues := default (dict) .Values.global -}}
17+
{{- $globalReplicaCount := -1 -}}
18+
{{- if and (kindIs "map" $globalValues) (hasKey $globalValues "network") -}}
19+
{{- $networkGlobal := index $globalValues "network" -}}
20+
{{- if and (kindIs "map" $networkGlobal) (hasKey $networkGlobal "validatorReplicaCount") -}}
21+
{{- $globalReplicaCount = (index $networkGlobal "validatorReplicaCount" | int) -}}
22+
{{- end -}}
23+
{{- end -}}
24+
{{- if and (eq $globalReplicaCount -1) (kindIs "map" $globalValues) (hasKey $globalValues "validatorReplicaCount") -}}
25+
{{- $globalReplicaCount = (index $globalValues "validatorReplicaCount" | int) -}}
26+
{{- end -}}
27+
{{- if eq $globalReplicaCount -1 -}}
28+
{{- fail (printf "artifacts.external.validators has %d entries. Set global.validatorReplicaCount (or global.network.validatorReplicaCount) to this value and align network-nodes.validatorReplicaCount." $validatorCount) -}}
29+
{{- end -}}
30+
{{- if ne $globalReplicaCount $validatorCount -}}
31+
{{- fail (printf "artifacts.external.validators has %d entries but the configured validator replica count is %d. Update global.validatorReplicaCount (or global.network.validatorReplicaCount) and network-nodes.validatorReplicaCount to match." $validatorCount $globalReplicaCount) -}}
32+
{{- end -}}
33+
apiVersion: v1
34+
kind: ConfigMap
35+
metadata:
36+
name: besu-genesis
37+
labels:
38+
{{- include "network-bootstrapper.labels" . | nindent 4 }}
39+
data:
40+
genesis.json: |-
41+
{{ toPrettyJson $genesis | indent 4 }}
42+
---
43+
apiVersion: v1
44+
kind: ConfigMap
45+
metadata:
46+
name: besu-static-nodes
47+
labels:
48+
{{- include "network-bootstrapper.labels" . | nindent 4 }}
49+
data:
50+
static-nodes.json: |-
51+
{{ toPrettyJson $staticNodes | indent 4 }}
52+
{{- range $index, $validator := $validators }}
53+
{{- $requiredAddress := required (printf "artifacts.external.validators[%d].address must be set." $index) $validator.address }}
54+
{{- $requiredPublicKey := required (printf "artifacts.external.validators[%d].publicKey must be set." $index) $validator.publicKey }}
55+
{{- $requiredPrivateKey := required (printf "artifacts.external.validators[%d].privateKey must be set." $index) $validator.privateKey }}
56+
{{- $requiredEnode := required (printf "artifacts.external.validators[%d].enode must be set." $index) $validator.enode }}
57+
---
58+
apiVersion: v1
59+
kind: ConfigMap
60+
metadata:
61+
name: {{ printf "besu-node-validator-%d-address" $index }}
62+
labels:
63+
{{- include "network-bootstrapper.labels" $root | nindent 4 }}
64+
data:
65+
address: {{ $requiredAddress | quote }}
66+
---
67+
apiVersion: v1
68+
kind: ConfigMap
69+
metadata:
70+
name: {{ printf "besu-node-validator-%d-enode" $index }}
71+
labels:
72+
{{- include "network-bootstrapper.labels" $root | nindent 4 }}
73+
data:
74+
enode: {{ $requiredEnode | quote }}
75+
---
76+
apiVersion: v1
77+
kind: ConfigMap
78+
metadata:
79+
name: {{ printf "besu-node-validator-%d-pubkey" $index }}
80+
labels:
81+
{{- include "network-bootstrapper.labels" $root | nindent 4 }}
82+
data:
83+
publicKey: {{ $requiredPublicKey | quote }}
84+
---
85+
apiVersion: v1
86+
kind: Secret
87+
metadata:
88+
name: {{ printf "besu-node-validator-%d-private-key" $index }}
89+
labels:
90+
{{- include "network-bootstrapper.labels" $root | nindent 4 }}
91+
type: Opaque
92+
stringData:
93+
privateKey: {{ $requiredPrivateKey | quote }}
94+
{{- end }}
95+
---
96+
apiVersion: v1
97+
kind: ConfigMap
98+
metadata:
99+
name: besu-faucet-address
100+
labels:
101+
{{- include "network-bootstrapper.labels" . | nindent 4 }}
102+
data:
103+
address: {{ $faucet.address | quote }}
104+
---
105+
apiVersion: v1
106+
kind: ConfigMap
107+
metadata:
108+
name: besu-faucet-pubkey
109+
labels:
110+
{{- include "network-bootstrapper.labels" . | nindent 4 }}
111+
data:
112+
publicKey: {{ $faucet.publicKey | quote }}
113+
---
114+
apiVersion: v1
115+
kind: Secret
116+
metadata:
117+
name: besu-faucet-private-key
118+
labels:
119+
{{- include "network-bootstrapper.labels" . | nindent 4 }}
120+
type: Opaque
121+
stringData:
122+
privateKey: {{ $faucet.privateKey | quote }}
123+
{{- end }}

charts/network/charts/network-bootstrapper/templates/job.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{{- $artifactSource := default "generated" .Values.artifacts.source -}}
2+
{{- if eq $artifactSource "generated" }}
13
apiVersion: batch/v1
24
kind: Job
35
metadata:
@@ -106,3 +108,4 @@ spec:
106108
tolerations:
107109
{{- toYaml . | nindent 8 }}
108110
{{- end }}
111+
{{- end }}

charts/network/charts/network-bootstrapper/values.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,22 @@ settings:
121121
evmStackSize:
122122
# -- (int) Maximum smart-contract bytecode size accepted by the EVM.
123123
contractSizeLimit:
124+
125+
# Artifact sourcing controls for bootstrap data used by the nodes chart.
126+
artifacts:
127+
# -- (string) Determines how Besu network artifacts are populated. Use `generated` to run the job or `external` to supply values manually.
128+
source: generated
129+
external:
130+
# -- (object) Besu genesis document rendered into the `besu-genesis` ConfigMap when `source` equals `external`.
131+
genesis: {}
132+
# -- (list) Collection of enode URIs persisted to the `besu-static-nodes` ConfigMap when `source` equals `external`.
133+
staticNodes: []
134+
# -- (list) Validator node definitions providing the data expected by the nodes chart. Each entry must include `address`, `publicKey`, `privateKey`, and `enode`.
135+
validators: []
136+
faucet:
137+
# -- (string) Faucet account address stored in the `besu-faucet-address` ConfigMap when `source` equals `external`.
138+
address: ""
139+
# -- (string) Faucet account public key stored in the `besu-faucet-pubkey` ConfigMap when `source` equals `external`.
140+
publicKey: ""
141+
# -- (string) Faucet private key stored in the `besu-faucet-private-key` Secret when `source` equals `external`.
142+
privateKey: ""

charts/network/charts/network-nodes/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,6 @@ A Helm chart for Kubernetes
135135
| serviceAccount.create | bool | `true` | Create a ServiceAccount resource automatically for the release. |
136136
| serviceAccount.name | string | `""` | Existing ServiceAccount name to reuse when creation is disabled. |
137137
| tolerations | list | `[]` | Tolerations allowing pods to run on nodes with matching taints. |
138-
| validatorReplicaCount | int | `4` | Number of validator node replicas participating in consensus. |
138+
| validatorReplicaCount | int | `nil` | Number of validator node replicas participating in consensus. Leave unset to derive from global.validatorReplicaCount. |
139139
| volumeMounts | list | `[]` | Additional volume mounts applied to Besu containers. |
140140
| volumes | list | `[]` | Extra volumes attached to Besu pods for custom configuration or secrets. |

0 commit comments

Comments
 (0)