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

Signer authorized keys #610

Merged
merged 7 commits into from
Nov 6, 2023
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
6 changes: 5 additions & 1 deletion charts/tezos/scripts/remote-signer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ CLIENT_DIR="$TEZ_VAR/client"
NODE_DIR="$TEZ_VAR/node"
NODE_DATA_DIR="$TEZ_VAR/node/data"

CMD="$TEZ_BIN/octez-signer -d $CLIENT_DIR launch http signer --magic-bytes 0x11,0x12,0x13 --check-high-watermark -a 0.0.0.0 -p 6732"
harryttd marked this conversation as resolved.
Show resolved Hide resolved
extra_args=""
if [ -f ${CLIENT_DIR}/authorized_keys ]; then
extra_args="${extra_args} --require-authentication"
fi
CMD="$TEZ_BIN/octez-signer -d $CLIENT_DIR ${extra_args} launch http signer -a 0.0.0.0 -p 6732"

# ensure we can run tezos-signer commands without specifying client dir
ln -s /var/tezos/client /home/tezos/.tezos-signer
Expand Down
28 changes: 28 additions & 0 deletions charts/tezos/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,31 @@ metadata:
{{- end }}
{{- "true" }}
{{- end }}

{{/*
Get list of authorized keys. Fails if any of the keys is not defined in the accounts.
*/}}
{{- define "tezos.getAuthorizedKeys" }}
{{- $allAuthorizedKeys := list }}
{{- /* Gather keys from nodes */}}
{{- range $node := .Values.nodes }}
{{- range $instance := $node.instances }}
{{- if .authorized_keys }}
{{- $allAuthorizedKeys = concat $allAuthorizedKeys .authorized_keys }}
{{- end }}
{{- end }}
{{- end }}
{{- /* Gather keys from octezSigners */}}
{{- range $signer := .Values.octezSigners }}
{{- if $signer.authorized_keys }}
{{- $allAuthorizedKeys = concat $allAuthorizedKeys $signer.authorized_keys }}
{{- end }}
{{- end }}
{{- /* Ensure all keys are defined in accounts and fail otherwise */}}
{{- $allAuthorizedKeys = uniq $allAuthorizedKeys }}
{{- range $key := $allAuthorizedKeys }}
{{- if not (index $.Values.accounts $key "key") }}
{{- fail (printf "Authorized key '%s' is not defined in accounts." $key) }}
{{- end }}
{{- end }}
{{- end }}
1 change: 1 addition & 0 deletions charts/tezos/templates/configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,4 @@ metadata:
namespace: {{ .Release.Namespace }}
---
{{- end }}
{{- include "tezos.getAuthorizedKeys" . }}
13 changes: 12 additions & 1 deletion charts/tezos/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ is_invitation: false

# Images not part of the tezos-k8s repo go here
images:
octez: tezos/tezos:v17.1
octez: tezos/tezos:v17.3
tacoinfraRemoteSigner: ghcr.io/oxheadalpha/tacoinfra-remote-signer:0.1.0
# Images that are part of the tezos-k8s repo go here with 'dev' tag
tezos_k8s_images:
Expand Down Expand Up @@ -174,6 +174,11 @@ should_generate_unsafe_deterministic_data: false
# Don't also set `bake_using_accounts`.
# - `bake_using_accounts`: List of account names that should be used for baking.
# Don't also set `bake_using_account`.
# - `authorized_keys`: List of account names that should be used as keys to
# authenticate a baker to a signer.
# When a baker uses a remote signer that requires
# authentication, the relevant key from this list
# will be used to sign every signature request.
# - `config`: Same as the outer statefulset level `config`. It overrides the
# statefulset level.
# - `is_bootstrap_node`: Boolean for is this node a bootstrap peer.
Expand Down Expand Up @@ -314,6 +319,12 @@ octezSigners: {}
# tezos-signer-0:
# accounts:
# - baker0
# authorized_keys:
# # Names of accounts used to authenticate the baker to the signer.
# # The baker must have the private key for one of the listed
# # accounts. The signer will only sign a request from a baker
# # authenticated by an allowed key.
# - authorized-key-0
# ```
#
# Deploys a signer using AWS KMS to sign operations.
Expand Down
2 changes: 1 addition & 1 deletion mkchain/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ You can explicitly specify some values by:
| | --number-of-nodes | Number of non-baking nodes in the cluster | 0 |
| bootstrap_peers | --bootstrap-peers | Peer ips to connect to | [] |
| expected_proof_of_work | --expected-proof-of-work | Node identity generation difficulty | 0 |
| images.octez | --octez-docker-image | Version of the Octez docker image to run | tezos/tezos:v17.1 |
| images.octez | --octez-docker-image | Version of the Octez docker image to run | tezos/tezos:v17.3 |
| | --use-docker (--no...) | Use (or don't use) docker to generate keys rather than pytezos | autodetect |
| zerotier_config.zerotier_network | --zerotier-network | Zerotier network id for external chain access | |
| zerotier_config.zerotier_token | --zerotier-token | Zerotier token for external chain access | |
Expand Down
14 changes: 8 additions & 6 deletions mkchain/tqchain/mkchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def quoted_scalar(dumper, data): # a representer to force quotations on scalars
},
"octez_docker_image": {
"help": "Version of the Octez docker image",
"default": "tezos/tezos:v17.1",
"default": "tezos/tezos:v17.3",
},
"use_docker": {
"action": "store_true",
Expand Down Expand Up @@ -154,6 +154,7 @@ def node_config(name, n, is_baker):
"shell": {"history_mode": "rolling"},
"metrics_addr": [":9932"],
},
"authorized_keys": ["authorized-key-0"],
}
if is_baker:
ret["bake_using_accounts"] = [f"{name}-{n}"]
Expand Down Expand Up @@ -243,7 +244,7 @@ def main():
baking_accounts = {
f"{ARCHIVE_BAKER_NODE_NAME}-{n}": {} for n in range(args.number_of_bakers)
}
for account in baking_accounts:
for account in [*baking_accounts, "authorized-key-0"]:
print(f"Generating keys for account {account}")
keys = gen_key(args.octez_docker_image)
for key_type in keys:
Expand Down Expand Up @@ -275,11 +276,12 @@ def main():
],
}

signers = {
octezSigners = {
"tezos-signer-0": {
"sign_for_accounts": [
"accounts": [
f"{ARCHIVE_BAKER_NODE_NAME}-{n}" for n in range(args.number_of_bakers)
]
],
"authorized_keys": ["authorized-key-0"],
}
}

Expand Down Expand Up @@ -308,7 +310,7 @@ def main():
**base_constants,
"bootstrap_peers": bootstrap_peers,
"accounts": accounts["secret"],
"signers": signers,
"octezSigners": octezSigners,
"nodes": creation_nodes,
**activation,
}
Expand Down
10 changes: 5 additions & 5 deletions test/charts/mainnet.expect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ data:
ARCHIVE_TARBALL_URL: ""
PREFER_TARBALLS: "false"
SNAPSHOT_SOURCE: "https://xtz-shots.io/tezos-snapshots.json"
OCTEZ_VERSION: "tezos/tezos:v17.1"
OCTEZ_VERSION: "tezos/tezos:v17.3"
NODE_GLOBALS: |
{
"config": {},
Expand Down Expand Up @@ -128,7 +128,7 @@ spec:
spec:
containers:
- name: octez-node
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down Expand Up @@ -213,7 +213,7 @@ spec:
memory: 80Mi
initContainers:
- name: config-init
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down Expand Up @@ -324,7 +324,7 @@ spec:
- mountPath: /var/tezos
name: var-volume
- name: snapshot-importer
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down Expand Up @@ -387,7 +387,7 @@ spec:
- mountPath: /var/tezos
name: var-volume
- name: upgrade-storage
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down
10 changes: 5 additions & 5 deletions test/charts/mainnet2.expect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ data:
ARCHIVE_TARBALL_URL: ""
PREFER_TARBALLS: "false"
SNAPSHOT_SOURCE: "https://xtz-shots.io/tezos-snapshots.json"
OCTEZ_VERSION: "tezos/tezos:v17.1"
OCTEZ_VERSION: "tezos/tezos:v17.3"
NODE_GLOBALS: |
{
"config": {},
Expand Down Expand Up @@ -195,7 +195,7 @@ spec:
spec:
containers:
- name: octez-node
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down Expand Up @@ -316,7 +316,7 @@ spec:
memory: 80Mi
initContainers:
- name: config-init
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down Expand Up @@ -433,7 +433,7 @@ spec:
- mountPath: /var/tezos
name: var-volume
- name: snapshot-importer
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down Expand Up @@ -498,7 +498,7 @@ spec:
- mountPath: /var/tezos
name: var-volume
- name: upgrade-storage
image: "tezos/tezos:v17.1"
image: "tezos/tezos:v17.3"
imagePullPolicy: IfNotPresent
command:
- /bin/sh
Expand Down
6 changes: 5 additions & 1 deletion test/charts/private-chain.expect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1561,7 +1561,11 @@ spec:
NODE_DIR="$TEZ_VAR/node"
NODE_DATA_DIR="$TEZ_VAR/node/data"

CMD="$TEZ_BIN/octez-signer -d $CLIENT_DIR launch http signer --magic-bytes 0x11,0x12,0x13 --check-high-watermark -a 0.0.0.0 -p 6732"
extra_args=""
if [ -f ${CLIENT_DIR}/authorized_keys ]; then
extra_args="${extra_args} --require-authentication"
fi
CMD="$TEZ_BIN/octez-signer -d $CLIENT_DIR ${extra_args} launch http signer -a 0.0.0.0 -p 6732"

# ensure we can run tezos-signer commands without specifying client dir
ln -s /var/tezos/client /home/tezos/.tezos-signer
Expand Down
30 changes: 28 additions & 2 deletions utils/config-generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,17 @@ def expose_secret_key(account_name):
pod. It returns the obvious Boolean.
"""
if MY_POD_TYPE == "activating":
all_authorized_keys = [
key
for node in NODES.values()
for instance in node["instances"]
for key in instance.get("authorized_keys", [])
]
if account_name in all_authorized_keys:
# Populate authorized keys known by all bakers in the activation account.
# This ensures that activation will succeed with a remote signer that requires auth,
# regardless of which baker does it.
Comment on lines +342 to +344
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically the activation pod is is doing the operation, not a baker, right? And security isn't such an issue, because once the chain is activated, activation params can be commented out in values.yaml and the activation pod won't be created anymore to have keys mounted.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, right, it probably does not have to be a baker, since at block 0, the list of bakers is not known... But what's the alternative? create a dedicated list of authorized_keys for activation? I've never activated a chain with an account that's not a baker, so I think it's fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i think it's fine as is.

What could be done is look up the signer that is signing for the baker baking with the activation key, get this signer's auth keys, and then only import those keys. If no signer is found, then no auth key would be required for activation.

return True
return NETWORK_CONFIG["activation_account_name"] == account_name

if MY_POD_TYPE == "signing":
Expand All @@ -340,6 +351,8 @@ def expose_secret_key(account_name):
if MY_POD_TYPE == "node":
if MY_POD_CONFIG.get("bake_using_account", "") == account_name:
return True
if account_name in MY_POD_CONFIG.get("authorized_keys", {}):
return True
return account_name in MY_POD_CONFIG.get("bake_using_accounts", {})

return False
Expand Down Expand Up @@ -419,6 +432,7 @@ def import_keys(all_accounts):
secret_keys = []
public_keys = []
public_key_hashs = []
authorized_keys = []

for account_name, account_values in all_accounts.items():
print("\n Importing keys for account: " + account_name)
Expand Down Expand Up @@ -453,6 +467,12 @@ def import_keys(all_accounts):
public_key_hashs.append({"name": account_name, "value": pkh_b58})
account_values["pkh"] = pkh_b58

if MY_POD_TYPE == "signing" and account_name in MY_POD_CONFIG.get(
"authorized_keys", {}
):
print(f" Appending authorized key: {pk_b58}")
authorized_keys.append({"name": account_name, "value": pk_b58})

print(f" Account key type: {account_values.get('type')}")
print(
f" Account bootstrap balance: "
Expand All @@ -463,17 +483,21 @@ def import_keys(all_accounts):
+ f"{account_values.get('is_bootstrap_baker_account', False)}"
)

sk_path, pk_path, pkh_path = (
sk_path, pk_path, pkh_path, ak_path = (
f"{tezdir}/secret_keys",
f"{tezdir}/public_keys",
f"{tezdir}/public_key_hashs",
f"{tezdir}/authorized_keys",
)
print(f"\n Writing {sk_path}")
json.dump(secret_keys, open(sk_path, "w"), indent=4)
print(f" Writing {pk_path}")
json.dump(public_keys, open(pk_path, "w"), indent=4)
print(f" Writing {pkh_path}")
json.dump(public_key_hashs, open(pkh_path, "w"), indent=4)
if MY_POD_TYPE == "signing" and len(authorized_keys) > 0:
harryttd marked this conversation as resolved.
Show resolved Hide resolved
print(f" Writing {ak_path}")
json.dump(authorized_keys, open(ak_path, "w"), indent=4)


def create_node_identity_json():
Expand Down Expand Up @@ -739,7 +763,9 @@ def create_node_snapshot_config_json(history_mode):
]
if octez_version:
matching_snapshots = [
s for s in matching_snapshots if int(octez_version) == s.get("tezos_version").get("version").get("major")
s
for s in matching_snapshots
if int(octez_version) == s.get("tezos_version").get("version").get("major")
]
matching_snapshots = sorted(matching_snapshots, key=lambda s: s.get("block_height"))

Expand Down
Loading