Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(substrate): multi-organization support #2641

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
365 changes: 313 additions & 52 deletions platforms/substrate/charts/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: "{{ $fullname }}-listener"
namespace: {{ $.Values.namespace }}
namespace: {{ $.Release.Namespace }}
spec:
port: {{ $.Values.proxy.port }}
protocol: TCP
Expand All @@ -59,8 +59,8 @@ apiVersion: getambassador.io/v3alpha1
kind: TCPMapping
metadata:
name: "{{ $fullname }}-tcpmapping"
namespace: {{ $.Values.namespace }}
namespace: {{ $.Release.Namespace }}
spec:
port: {{ $.Values.proxy.port }}
service: "{{ $fullname }}-swarm.{{ $.Values.namespace }}:{{ $.Values.config.ipfsSwarmPort }}"
service: "{{ $fullname }}-swarm.{{ $.Release.Namespace }}:{{ $.Values.config.ipfsSwarmPort }}"
{{- end }}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ spec:

peer_id=$(cat config | jq -r .Identity.PeerID)
private_key=$(cat config | jq -r .Identity.PrivKey)
echo "peer_id: ${peer_id}"

{{- if eq .Values.global.vault.type "hashicorp" }}
echo "
Expand All @@ -169,7 +170,7 @@ spec:
jq -r 'if .errors then . else .auth.client_token end')

validateVaultResponse 'vault login token' "${VAULT_CLIENT_TOKEN}"
vault_secret_key="${VAULT_SECRET_ENGINE}"/"${VAULT_SECRET_PREFIX}-ipfs-keys"
vault_secret_key="${VAULT_SECRET_ENGINE}"/"${VAULT_SECRET_PREFIX}/{{ .Release.Name }}-ipfs-keys"
# Save the generated keys to VAULT
LOOKUP_SECRET_RESPONSE=$(curl -sS -H "X-Vault-Token: ${VAULT_CLIENT_TOKEN}" \
-H "Content-Type: application/json" \
Expand Down
5 changes: 3 additions & 2 deletions platforms/substrate/charts/dscp-ipfs-node/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ config:
healthCheckPollPeriod: 30000
healthCheckTimeout: 2000
# External DSCP-Node hostname to query, this overrides dscpNode.enabled
nodeHost: member-1-substrate-node
# nodeHost: oem-member-1-node-substrate-node-0 # member-1-substrate-node
nodeHost:
# External DSCP-Node port to query
nodePort: 9944
# Public key for the IPFS subsystem
Expand All @@ -66,7 +67,7 @@ config:
ipfsLogLevel: info
# IPFS boot node addresses in MultiAddress format for the IPFS subsystem
## ref: https://multiformats.io/multiaddr/
ipfsBootNodeAddress: ""
ipfsBootNodeAddress:

service:
# dscp-ipfs swarm service configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,7 @@ spec:
args:
- |
{{- if .Values.removeGenesisOnDelete.enabled }}
secret_names=$(kubectl get secret -n {{ .Release.Namespace }} | grep substrate-node | awk '{print $1}')

while IFS= read -r nodeKeys; do
kubectl delete secret "$nodeKeys" --namespace {{ .Release.Namespace }}
done <<< "$secret_names"

if kubectl get configmap "substrate-genesis" --namespace {{ .Release.Namespace }} &> /dev/null; then
kubectl delete configmap "substrate-genesis" --namespace {{ .Release.Namespace }}
kubectl delete configmap "substrate-genesis" --namespace {{ .Release.Namespace }}
fi
{{- end}}
137 changes: 80 additions & 57 deletions platforms/substrate/charts/substrate-genesis/templates/genesis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ spec:
chmod +x kubectl
mv kubectl /usr/local/bin/
kubectl version --client

echo "Step 2: Execute the provided command to generate the genesis block."
mkdir certcheck
command={{ $.Values.node.command }}
echo "Generate genesis"
GENESIS=$($command build-spec --disable-default-bootnode --chain local)

echo "Step 3: Edit genesis configuration."
# Set values
GENESIS=$(echo $GENESIS | jq '.name |= {{ .Values.chain | quote }}')
Expand All @@ -114,7 +114,7 @@ spec:
GENESIS=$(echo $GENESIS | jq '.genesis.runtime.nodeAuthorization.nodes |= []')
GENESIS=$(echo $GENESIS | jq '.genesis.runtime.membership.members |= []')
{{- end }}

echo "Step 4: Generate sudo key with Sr25519 scheme and add sudo account key and balance into genesis."
# Generate sudo key with Sr25519 scheme
$command key generate --scheme Sr25519 --output-type json >> certcheck/sudoKeygenOutput.json
Expand All @@ -123,80 +123,103 @@ spec:
# Add sudo account key and balance into genesis
GENESIS=$(echo $GENESIS | jq --arg sudo $SUDO_ADDR --arg balance 1152921504606846976 '.genesis.runtime.balances.balances += [[$sudo, ($balance | tonumber)]]')
GENESIS=$(echo $GENESIS | jq --arg sudo $SUDO_ADDR '.genesis.runtime.sudo.key |= $sudo')

echo "Step 5: Insert AURA & GRANDPA keys into genesis for validators."
echo "Inserting keys into genesis for validators"
for ((i=1; i<={{ $.Values.node.validator.count }}; i++)); do
secret_data=$(kubectl get secret "substrate-node-validator-${i}-keys" --namespace {{ .Release.Namespace }} -o json | jq -r '.data["substrate-node-keys"]' | base64 -d)

# Iterate over each organization namespace
{{- range .Values.org_namespaces }}
# Extract the org name (first key in the current item)
{{- $org_name := . | keys | first }}
# Access the 'validator' list using the index function and print each validator
{{- $validators := index . $org_name "validator" }}

# Check if secret_data is empty or not
if [ -n "$secret_data" ]; then
# Extract aura_addr and grandpa_addr
aura_addr=$(echo "$secret_data" | jq -r '.data.aura_addr')
grandpa_addr=$(echo "$secret_data" | jq -r '.data.grandpa_addr')
{{- range $validators }}
echo " Validator: {{ . }}"
secret_data=$(kubectl get secret "{{ . }}-keys" --namespace {{ $org_name }} -o json | jq -r '.data["substrate-node-keys"]' | base64 -d)

# Check if extraction successful
if [ -n "$aura_addr" ] && [ -n "$grandpa_addr" ]; then
# Insert aura_addr keys into GENESIS JSON
GENESIS=$(echo "$GENESIS" | jq --arg aura "$aura_addr" '.genesis.runtime.aura.authorities += [$aura]')
GENESIS=$(echo "$GENESIS" | jq --arg grandpa "$grandpa_addr" '.genesis.runtime.grandpa.authorities += [[$grandpa, 1]]')
# Check if secret_data is empty or not
if [ -n "$secret_data" ]; then
# Extract aura_addr and grandpa_addr
aura_addr=$(echo "$secret_data" | jq -r '.data.aura_addr')
grandpa_addr=$(echo "$secret_data" | jq -r '.data.grandpa_addr')

# Check if extraction successful
if [ -n "$aura_addr" ] && [ -n "$grandpa_addr" ]; then
# Insert aura_addr keys into GENESIS JSON
GENESIS=$(echo "$GENESIS" | jq --arg aura "$aura_addr" '.genesis.runtime.aura.authorities += [$aura]')
GENESIS=$(echo "$GENESIS" | jq --arg grandpa "$grandpa_addr" '.genesis.runtime.grandpa.authorities += [[$grandpa, 1]]')
else
echo "Error: Unable to retrieve aura_addr or grandpa_addr key for validator $validator"
fi
else
echo "Error: Unable to retrieve aura_addr or grandpa_addr key"
echo "Error: Unable to retrieve aura_addr or grandpa_addr key for validator $validator."
fi
else
echo "Error: Unable to retrieve data."
fi
done

# Initialize an array to store each nodes' Kubernetes secret name
secret_names=$(kubectl get secret -n {{ .Release.Namespace }} | grep substrate-node | awk '{print $1}')
declare -a nodes
while IFS= read -r line; do
nodes+=("$line")
done <<< "$secret_names"

{{- end }}
{{- end }}
echo "Key insertion process completed."

echo "Step 6: Adding member accounts and their balances to genesis."
for ((i=1; i<={{ $.Values.node.member.count }}; i++)); do
account_addr=$(kubectl get secret "substrate-node-member-$i-keys" --namespace {{ .Release.Namespace }} -o json | jq -r '.data["substrate-node-keys"]' | base64 -d | jq -r '.data.account_addr')
# Add account address and balance into genesis block
GENESIS=$(echo "$GENESIS" | jq --arg account_id "$account_addr" --arg balance {{ $.Values.node.member.balance }} '.genesis.runtime.balances.balances += [[$account_id, ($balance | tonumber)]]')
GENESIS=$(echo "$GENESIS" | jq --arg account_id "$account_addr" '.genesis.runtime.membership.members += [$account_id]')
{{- range .Values.org_namespaces }}
# Extract the org name (first key in the current item)
{{- $org_name := . | keys | first }}
# Access the 'member' list
{{- $members := index . $org_name "member" }}
# Access the 'validator' list
{{- $validators := index . $org_name "validator" }}

# Loop through each node to add authorization for the current member
for node in "${nodes[@]}"; do
# Retrieve node ID for the current node
node_id=$(kubectl get secret "$node" --namespace {{ .Release.Namespace }} -o json | jq -r '.data["substrate-node-keys"]' | base64 -d | jq -r '.data.node_id')
# Iterate through members
{{- range $members }}
account_addr=$(kubectl get secret "{{ . }}-keys" --namespace "{{ $org_name }}" -o json | jq -r '.data["substrate-node-keys"]' | base64 -d | jq -r '.data.account_addr')

# Convert node ID to base58 format
base58=$(echo -n "$node_id" | base58 -d | xxd -p | tr -d '[:space:]' | tr '[:lower:]' '[:upper:]')
GENESIS=$(echo "$GENESIS" | jq --arg account_id "$account_addr" --arg balance {{ $.Values.node.member.balance }} '.genesis.runtime.balances.balances += [[$account_id, ($balance | tonumber)]]')
GENESIS=$(echo "$GENESIS" | jq --arg account_id "$account_addr" '.genesis.runtime.membership.members += [$account_id]')

# Split the base58 string into an array of bytes
arr_node_id=($(echo $base58 | fold -w2))

# Add authorization for the current member to the node
GENESIS=$(echo $GENESIS | jq --arg owner "$account_addr" '.genesis.runtime.nodeAuthorization.nodes += [[[], $owner]]')
for byte in "${arr_node_id[@]}"
do
# Add each byte of the node ID to the authorization
GENESIS=$(echo $GENESIS | jq --arg byte $(echo "obase=10; ibase=16; $byte" | bc) '.genesis.runtime.nodeAuthorization.nodes[-1][0] += [($byte | tonumber)]')
done
done
done
{{- range $validators }}
node_id=$(kubectl get secret "{{ . }}-keys" --namespace "{{ $org_name }}" -o json | jq -r '.data["substrate-node-keys"]' | base64 -d | jq -r '.data.node_id')
base58=$(echo -n "$node_id" | base58 -d | xxd -p | tr -d '[:space:]' | tr '[:lower:]' '[:upper:]')
arr_node_id=($(echo $base58 | fold -w2))
GENESIS=$(echo $GENESIS | jq --arg owner "$account_addr" '.genesis.runtime.nodeAuthorization.nodes += [[[], $owner]]')
for byte in "${arr_node_id[@]}"
do
# Add each byte of the node ID to the authorization
GENESIS=$(echo $GENESIS | jq --arg byte $(echo "obase=10; ibase=16; $byte" | bc) '.genesis.runtime.nodeAuthorization.nodes[-1][0] += [($byte | tonumber)]')
done
{{- end }}
{{- range $members }}
node_id=$(kubectl get secret "{{ . }}-keys" --namespace "{{ $org_name }}" -o json | jq -r '.data["substrate-node-keys"]' | base64 -d | jq -r '.data.node_id')
base58=$(echo -n "$node_id" | base58 -d | xxd -p | tr -d '[:space:]' | tr '[:lower:]' '[:upper:]')
arr_node_id=($(echo $base58 | fold -w2))
GENESIS=$(echo $GENESIS | jq --arg owner "$account_addr" '.genesis.runtime.nodeAuthorization.nodes += [[[], $owner]]')
for byte in "${arr_node_id[@]}"
do
# Add each byte of the node ID to the authorization
GENESIS=$(echo $GENESIS | jq --arg byte $(echo "obase=10; ibase=16; $byte" | bc) '.genesis.runtime.nodeAuthorization.nodes[-1][0] += [($byte | tonumber)]')
done
{{- end }}
{{- end }}
{{- end }}

echo "Step 7: Update the format of the modified genesis JSON and create a config map if it doesn't exist."
# Write the modified genesis JSON to a file
echo "$GENESIS" > certcheck/genesis.json

# Convert the genesis JSON to raw format
echo "Converting genesis to raw format"
GENESIS=$($command build-spec --disable-default-bootnode --raw --chain certcheck/genesis.json)
echo "$GENESIS" > certcheck/genesis_raw.json
# Encode the raw genesis JSON to base64
cat certcheck/genesis_raw.json | base64 -w0 > certcheck/genesis_base64 # No need to encode it if you wanna store genesis as a K8s secret

# # Create the config map "substrate-genesis" using the base64 encoded genesis JSON and sudoKeygenOutput.json if it doesn't exist
if ! kubectl get configmap "substrate-genesis" --namespace {{ .Release.Namespace }} &> /dev/null; then
kubectl create configmap "substrate-genesis" --namespace {{ .Release.Namespace }} --from-file=genesis="${MOUNT_PATH}/genesis_base64" --from-file=sudoKeygenOutput="${MOUNT_PATH}/sudoKeygenOutput.json"
fi

{{- range .Values.org_namespaces }}
# Extract the org name (first key in the current item)
{{- $org_name := . | keys | first }}

# Create the config map "substrate-genesis" using the base64 encoded genesis JSON and sudoKeygenOutput.json if it doesn't exist
if ! kubectl get configmap "substrate-genesis" --namespace {{ $org_name }} &> /dev/null; then
kubectl create configmap "substrate-genesis" --namespace {{ $org_name }} --from-file=genesis="${MOUNT_PATH}/genesis_base64" --from-file=sudoKeygenOutput="${MOUNT_PATH}/sudoKeygenOutput.json"
fi
{{- end }}
echo "COMPLETED!"
{{- if eq .Values.global.vault.type "hashicorp" }}
# Initialize the token
Expand Down
33 changes: 24 additions & 9 deletions platforms/substrate/charts/substrate-genesis/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,28 @@
# The following are for overriding global values
global:
# Provide the service account name which will be created.
serviceAccountName: vault-auth
serviceAccountName: global-vault-sa
cluster:
provider: azure # choose from: minikube | aws
provider: # choose from: minikube | aws | azure
cloudNativeServices: false # 'false' is implemented
#Provide the kubernetes host url
#Eg. kubernetesUrl: https://10.3.8.5:6443
kubernetesUrl:
vault:
# Provide the type of vault
type: kubernetes # hashicorp | kubernetes
type: hashicorp # hashicorp | kubernetes
# Provide the vault role used.
role: vault-role
role: # global-vault-role
# Provide the network type
network: substrate
# Provide the vault server address
address: # "http://vault_url"
# Provide the vault authPath configured to be used.
authPath: supplychain
authPath: oem
# Provide the secret engine.
secretEngine: secretsv2
# Provide the vault path where the secrets will be stored
secretPrefix: "data/supplychain"
secretPrefix: "data/oem"

removeGenesisOnDelete:
enabled: true
Expand All @@ -59,8 +59,23 @@ node:
# Command to be invoked to perform operations on the node
# Eg. command: substrate
command: ./dscp-node
validator:
count: 4
member:
count: 1
balance: 1152921504606846976

org_namespaces:
- oem-subs:
validator:
- oem-validator-1
- oem-validator-2
member:
- oem-member-1
- tierone-subs:
validator:
- tierone-validator-3
- tierone-validator-4
member:
- tierone-member-2
- tiertwo-subs:
validator:
member:
- tiertwo-member-3
9 changes: 9 additions & 0 deletions platforms/substrate/charts/substrate-key-gen/Chart.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
dependencies:
- name: bevel-vault-mgmt
repository: file://../../../shared/charts/bevel-vault-mgmt
version: 1.0.1
- name: bevel-scripts
repository: file://../../../shared/charts/bevel-scripts
version: 1.0.0
digest: sha256:24f4543fa153ec12bce571445cb3cd5bf59e44e2f1177fb28299fa48865c5644
generated: "2024-12-10T09:26:12.553233538Z"
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,26 @@
#
# SPDX-License-Identifier: Apache-2.0
##############################################################################################

---
apiVersion: v2
name: substrate-key-mgmt
appVersion: 'latest'
name: substrate-key-gen
description: A Helm chart to generate the keys for Substrate Nodes
version: 1.1.0
type: application
annotations:
hyperledger-bevel/platform: substrate
licenses: Apache-2.0
home: https://github.com/hyperledger/bevel
version: 1.1.0
appVersion: latest
keywords:
- DSCP
- BEVEL
- SUBSTRATE
- bevel
- ethereum
- substrate
- hyperledger
- enterprise
- blockchain
- deployment
- accenture
home: https://hyperledger-bevel.readthedocs.io/en/latest/
sources:
- https://github.com/hyperledger/bevel
maintainers:
- name: Hyperledger Bevel maintainers
email: [email protected]
Loading
Loading