Skip to content

Commit

Permalink
feat: implement terraform for multichain (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
itegulov authored Dec 11, 2023
1 parent 0af4a25 commit b4a9eaa
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/terraform-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
id: init
run: terraform init -backend-config backend-config-dev.tfvars
run: terraform init
env:
GOOGLE_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS_DEV }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/terraform-feature-env-destroy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
id: init
run: terraform init -backend-config backend-config-dev.tfvars
run: terraform init
env:
GOOGLE_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS_DEV }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/terraform-feature-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
id: init
run: terraform init -backend-config backend-config-dev.tfvars
run: terraform init
env:
GOOGLE_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS_DEV }}

Expand Down
3 changes: 2 additions & 1 deletion contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ pub struct MpcContract {

#[near_bindgen]
impl MpcContract {
#[init]
// TODO: only add ignore_state for dev environments
#[init(ignore_state)]
pub fn init(threshold: usize, participants: BTreeMap<AccountId, ParticipantInfo>) -> Self {
MpcContract {
protocol_state: ProtocolContractState::Initializing(InitializingContractState {
Expand Down
142 changes: 142 additions & 0 deletions infra/modules/multichain/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
resource "google_cloud_run_v2_service" "node" {
name = var.service_name
location = var.region
ingress = "INGRESS_TRAFFIC_ALL"

template {
service_account = var.service_account_email

annotations = var.metadata_annotations == null ? null : var.metadata_annotations

scaling {
min_instance_count = 1
max_instance_count = 1
}

containers {
image = var.docker_image
args = ["start"]

env {
name = "MPC_RECOVERY_NODE_ID"
value = var.node_id
}
env {
name = "MPC_RECOVERY_NEAR_RPC"
value = var.near_rpc
}
env {
name = "MPC_RECOVERY_CONTRACT_ID"
value = var.mpc_contract_id
}
env {
name = "MPC_RECOVERY_ACCOUNT"
value = var.account
}
env {
name = "MPC_RECOVERY_CIPHER_PK"
value = var.cipher_pk
}
env {
name = "MPC_RECOVERY_LOCAL_ADDRESS"
value = var.my_address
}
env {
name = "MPC_RECOVERY_INDEXER_S3_BUCKET"
value = var.indexer_options.s3_bucket
}
env {
name = "MPC_RECOVERY_INDEXER_S3_REGION"
value = var.indexer_options.s3_region
}
// Conditional block in case s3_url is present. See https://stackoverflow.com/a/69891235
dynamic "env" {
for_each = var.indexer_options.s3_url == null ? [] : [1]
content {
name = "MPC_RECOVERY_INDEXER_S3_URL"
value = var.indexer_options.s3_url
}
}
env {
name = "MPC_RECOVERY_INDEXER_START_BLOCK_HEIGHT"
value = var.indexer_options.start_block_height
}
env {
name = "MPC_RECOVERY_ACCOUNT_SK"
value_source {
secret_key_ref {
secret = var.account_sk_secret_id
version = "latest"
}
}
}
env {
name = "MPC_RECOVERY_CIPHER_SK"
value_source {
secret_key_ref {
secret = var.cipher_sk_secret_id
version = "latest"
}
}
}
env {
name = "AWS_ACCESS_KEY_ID"
value_source {
secret_key_ref {
secret = var.aws_access_key_secret_id
version = "latest"
}
}
}
env {
name = "AWS_SECRET_ACCESS_KEY"
value_source {
secret_key_ref {
secret = var.aws_secret_key_secret_id
version = "latest"
}
}
}
env {
name = "AWS_DEFAULT_REGION"
value = var.indexer_options.s3_region
}

env {
name = "MPC_RECOVERY_WEB_PORT"
value = "3000"
}
env {
name = "RUST_LOG"
value = "mpc_recovery_node=debug"
}

ports {
container_port = 3000
}

resources {
cpu_idle = false

limits = {
cpu = 2
memory = "2Gi"
}
}
}
}
}

// Allow unauthenticated requests
resource "google_cloud_run_v2_service_iam_member" "allow_all" {
project = google_cloud_run_v2_service.node.project
location = google_cloud_run_v2_service.node.location
name = google_cloud_run_v2_service.node.name

role = "roles/run.invoker"
member = "allUsers"

depends_on = [
google_cloud_run_v2_service.node
]
}
3 changes: 3 additions & 0 deletions infra/modules/multichain/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "node" {
value = google_cloud_run_v2_service.node
}
69 changes: 69 additions & 0 deletions infra/modules/multichain/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
variable "region" {
}

variable "service_account_email" {
}

variable "docker_image" {
}

variable "metadata_annotations" {
type = map(any)
default = null
description = "Annotations for the metadata associated with this Service."
}

# Application variables
variable "node_id" {
type = number
}

variable "near_rpc" {
type = string
}

variable "mpc_contract_id" {
type = string
}

variable "account" {
type = string
}

variable "cipher_pk" {
type = string
}

variable "my_address" {
type = string
}

variable "indexer_options" {
type = object({
s3_bucket = string
s3_region = string
s3_url = optional(string)
start_block_height = number
})
}

variable "service_name" {
type = string
}

# Secrets
variable "account_sk_secret_id" {
type = string
}

variable "cipher_sk_secret_id" {
type = string
}

variable "aws_access_key_secret_id" {
type = string
}

variable "aws_secret_key_secret_id" {
type = string
}
1 change: 0 additions & 1 deletion infra/mpc-recovery-dev/backend-config-dev.tfvars

This file was deleted.

113 changes: 113 additions & 0 deletions infra/multichain-dev/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
terraform {
backend "gcs" {
bucket = "multichain-terraform-dev"
prefix = "state/multichain"
}

required_providers {
google = {
source = "hashicorp/google"
version = "4.73.0"
}
}
}

locals {
credentials = var.credentials != null ? var.credentials : file(var.credentials_file)
client_email = jsondecode(local.credentials).client_email
client_id = jsondecode(local.credentials).client_id

workspace = {
near_rpc = "https://rpc.testnet.near.org"
}
}

data "external" "git_checkout" {
program = ["${path.module}/../scripts/get_sha.sh"]
}

provider "google" {
credentials = local.credentials

project = var.project
region = var.region
zone = var.zone
}

/*
* Create brand new service account with basic IAM
*/
resource "google_service_account" "service_account" {
account_id = "multichain-${var.env}"
display_name = "Multichain ${var.env} Account"
}

resource "google_service_account_iam_binding" "serivce-account-iam" {
service_account_id = google_service_account.service_account.name
role = "roles/iam.serviceAccountUser"

members = [
"serviceAccount:${local.client_email}",
]
}

/*
* Ensure service account has access to Secret Manager variables
*/
resource "google_secret_manager_secret_iam_member" "account_sk_secret_access" {
count = length(var.node_configs)

secret_id = var.node_configs[count.index].account_sk_secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.service_account.email}"
}

resource "google_secret_manager_secret_iam_member" "cipher_sk_secret_access" {
count = length(var.node_configs)

secret_id = var.node_configs[count.index].cipher_sk_secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.service_account.email}"
}

resource "google_secret_manager_secret_iam_member" "aws_access_key_secret_access" {
secret_id = var.aws_access_key_secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.service_account.email}"
}

resource "google_secret_manager_secret_iam_member" "aws_secret_key_secret_access" {
secret_id = var.aws_secret_key_secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.service_account.email}"
}

module "node" {
count = length(var.node_configs)
source = "../modules/multichain"

service_name = "multichain-${var.env}-${count.index}"
region = var.region
service_account_email = google_service_account.service_account.email
docker_image = var.docker_image

node_id = count.index
near_rpc = local.workspace.near_rpc
mpc_contract_id = var.mpc_contract_id
account = var.node_configs[count.index].account
cipher_pk = var.node_configs[count.index].cipher_pk
indexer_options = var.indexer_options
my_address = var.node_configs[count.index].address

account_sk_secret_id = var.node_configs[count.index].account_sk_secret_id
cipher_sk_secret_id = var.node_configs[count.index].cipher_sk_secret_id
aws_access_key_secret_id = var.aws_access_key_secret_id
aws_secret_key_secret_id = var.aws_secret_key_secret_id

depends_on = [
google_secret_manager_secret_iam_member.account_sk_secret_access,
google_secret_manager_secret_iam_member.cipher_sk_secret_access,
google_secret_manager_secret_iam_member.aws_access_key_secret_access,
google_secret_manager_secret_iam_member.aws_secret_key_secret_access
]
}
Loading

0 comments on commit b4a9eaa

Please sign in to comment.