diff --git a/examples/validator-vfn/.env.example b/examples/validator-vfn/.env.example index 8de3f98..9b6a190 100644 --- a/examples/validator-vfn/.env.example +++ b/examples/validator-vfn/.env.example @@ -52,28 +52,25 @@ DEPLOY_FULLNODE=false # Kubernetes Configuration (optional) # NAMESPACE=movement-l1 -# Validator Identity Secret +# Identity Secrets # -# OPTION 1: Automatic - Use AWS Secrets Manager (Recommended) -# Store your validator keys in AWS Secrets Manager, and Terraform will automatically -# create the Kubernetes secret for you. +# Resolution order per identity (deploy fails if neither is set): +# 1. _KEYS_SECRET_NAME → read from AWS Secrets Manager (preferred) +# 2. _IDENTITY_FILE → read from local file (fallback) # -# Steps: -# 1. Generate keys: aptos genesis generate-keys --output-dir ./keys -# 2. Store in AWS: aws secretsmanager create-secret \ -# --name movement/validator-01/validator-identity \ -# --secret-string file://keys/validator-identity.yaml -# 3. Set the secret name below +# If the ASM var is set, the local file is ignored. ASM failures are NOT caught — +# they error out instead of silently falling back, to avoid running with the +# wrong identity. # +# Validator identity # VALIDATOR_KEYS_SECRET_NAME=movement/validator-01/validator-identity -# -# OPTION 2: Manual - Create Kubernetes Secret Manually -# Leave VALIDATOR_KEYS_SECRET_NAME empty and create the secret manually: -# kubectl create namespace movement-l1 -# kubectl create secret generic validator-identity \ -# --from-file=validator-identity.yaml=./keys/validator-identity.yaml \ -# -n movement-l1 -# +# VALIDATOR_IDENTITY_FILE=./keys/validator-identity.yaml VALIDATOR_KEYS_SECRET_NAME= -# This is K8s secrete name where used by k8s for indexing the secrets +# K8s Secret object name the chart mounts (rarely needs changing) VALIDATOR_KEYS_SECRET=validator-identity + +# VFN identity (only used when DEPLOY_VFN=true) +# VFN_KEYS_SECRET_NAME=movement/validator-01/vfn-identity +# VFN_IDENTITY_FILE=./keys/validator-full-node-identity.yaml +VFN_KEYS_SECRET_NAME= +VFN_KEYS_SECRET=vfn-identity diff --git a/examples/validator-vfn/deploy.py b/examples/validator-vfn/deploy.py index c8e8f31..3592b34 100644 --- a/examples/validator-vfn/deploy.py +++ b/examples/validator-vfn/deploy.py @@ -37,25 +37,17 @@ def create_validator_secret_from_aws_sm( namespace: str, secret_name: str, aws_secret_name: str, + secret_key: str, region: str, profile: str | None = None, ) -> None: - """Create Kubernetes secret from AWS Secrets Manager. - - Args: - namespace: Kubernetes namespace - secret_name: Name for the Kubernetes secret - aws_secret_name: AWS Secrets Manager secret name - region: AWS region - profile: AWS profile to use (optional) - """ + """Create Kubernetes secret from AWS Secrets Manager.""" try: import boto3 from kubernetes import client, config - info(f"Reading validator identity from AWS Secrets Manager: {aws_secret_name}") + info(f"Reading identity from AWS Secrets Manager: {aws_secret_name}") - # Read from AWS Secrets Manager if profile: session = boto3.Session(profile_name=profile) sm_client = session.client("secretsmanager", region_name=region) @@ -64,11 +56,9 @@ def create_validator_secret_from_aws_sm( response = sm_client.get_secret_value(SecretId=aws_secret_name) secret_data = response["SecretString"] - # Connect to Kubernetes config.load_kube_config() v1 = client.CoreV1Api() - # Check if secret already exists try: v1.read_namespaced_secret(secret_name, namespace) info(f" Secret '{secret_name}' already exists in namespace '{namespace}'") @@ -77,10 +67,9 @@ def create_validator_secret_from_aws_sm( if e.status != 404: raise - # Create Kubernetes secret using string_data (no base64 encoding needed) k8s_secret = client.V1Secret( metadata=client.V1ObjectMeta(name=secret_name), - string_data={"validator-identity.yaml": secret_data}, + string_data={secret_key: secret_data}, type="Opaque", ) @@ -522,35 +511,69 @@ def deploy(env_vars: dict, force_create: bool, validate: bool, terraform_dir: Pa eks.wait_until_active() eks.update_kubeconfig() - # Step 1.5: Create identity secrets from local files + # Step 1.5: Create identity secrets — AWS Secrets Manager first, local file fallback info("\n" + "=" * 80) info("Creating Kubernetes Identity Secrets") info("=" * 80) - # Validator identity secret - validator_identity_file = env_vars.get("VALIDATOR_IDENTITY_FILE", "") - if validator_identity_file: - create_identity_secret_from_local_file( - namespace=namespace, - secret_name=validator_keys_secret, - local_file_path=Path(validator_identity_file), - secret_key="validator-identity.yaml", - ) - else: - info(f" No VALIDATOR_IDENTITY_FILE set (using existing K8s secret: {validator_keys_secret})") + def provision_identity( + label: str, + k8s_secret_name: str, + secret_key: str, + asm_env: str, + file_env: str, + ) -> None: + asm_name = env_vars.get(asm_env, "").strip() + local_file = env_vars.get(file_env, "").strip() + + if asm_name: + create_validator_secret_from_aws_sm( + namespace=namespace, + secret_name=k8s_secret_name, + aws_secret_name=asm_name, + secret_key=secret_key, + region=region, + profile=profile, + ) + return - # VFN identity secret (only if deploying VFN) - if deploy_vfn: - vfn_identity_file = env_vars.get("VFN_IDENTITY_FILE", "") - if vfn_identity_file: - create_identity_secret_from_local_file( + if local_file: + ok = create_identity_secret_from_local_file( namespace=namespace, - secret_name=vfn_keys_secret, - local_file_path=Path(vfn_identity_file), - secret_key="validator-full-node-identity.yaml", + secret_name=k8s_secret_name, + local_file_path=Path(local_file), + secret_key=secret_key, ) - else: - info(f" No VFN_IDENTITY_FILE set (using existing K8s secret: {vfn_keys_secret})") + if not ok: + error( + f"{label}: {file_env}={local_file} but file does not exist. " + f"Set {asm_env} to use AWS Secrets Manager or fix the path." + ) + sys.exit(1) + return + + error( + f"{label}: no identity source configured. " + f"Set {asm_env} (AWS Secrets Manager, preferred) or {file_env} (local file)." + ) + sys.exit(1) + + provision_identity( + label="Validator identity", + k8s_secret_name=validator_keys_secret, + secret_key="validator-identity.yaml", + asm_env="VALIDATOR_KEYS_SECRET_NAME", + file_env="VALIDATOR_IDENTITY_FILE", + ) + + if deploy_vfn: + provision_identity( + label="VFN identity", + k8s_secret_name=vfn_keys_secret, + secret_key="validator-full-node-identity.yaml", + asm_env="VFN_KEYS_SECRET_NAME", + file_env="VFN_IDENTITY_FILE", + ) # Step 2: Deploy nodes in order from tools.helm import HelmManager