diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca8e55b..ffd4c52 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -125,6 +125,8 @@ plan_satapi: -var "charge_token=$CHARGE_TOKEN" -var "rpcpass=$RPCPASS" -var "k8s_autossh_lb=$GKE_LB" + -var "station1=$STATION_1" + -var "station2=$STATION_2" -input=false) # This plan gets triggered only for miscellaneous branches/tags (i.e. tor, prometheus, etc), so make sure the branch/tag name starts with misc_ @@ -213,6 +215,8 @@ plan_staging: -var "charge_token=$CHARGE_TOKEN" -var "rpcpass=$RPCPASS" -var "k8s_autossh_lb=$GKE_LB" + -var "station1=$STATION_1" + -var "station2=$STATION_2" -input=false) # Tag with staging_v.* to deploy mainnet + LB to staging (e.g. staging_v0.1.1) @@ -246,6 +250,8 @@ deploy_staging: -var "charge_token=$CHARGE_TOKEN" -var "rpcpass=$RPCPASS" -var "k8s_autossh_lb=$GKE_LB" + -var "station1=$STATION_1" + -var "station2=$STATION_2" -input=false -auto-approve) # Tag with prod_v.* to plan mainnet + LB to production (e.g. prod_v0.1.1) @@ -278,6 +284,8 @@ plan_production: -var "charge_token=$CHARGE_TOKEN" -var "rpcpass=$RPCPASS" -var "k8s_autossh_lb=$GKE_LB" + -var "station1=$STATION_1" + -var "station2=$STATION_2" -input=false) # Tag with prod_v.* to deploy mainnet + LB to production (e.g. prod_v0.1.1) @@ -311,6 +319,8 @@ deploy_production: -var "charge_token=$CHARGE_TOKEN" -var "rpcpass=$RPCPASS" -var "k8s_autossh_lb=$GKE_LB" + -var "station1=$STATION_1" + -var "station2=$STATION_2" -input=false -auto-approve) # Tag with testnet_staging_v.* to plan testnet staging (e.g. testnet_staging_v0.1.1) diff --git a/terraform/data.tf b/terraform/data.tf index 55a0b9f..44dbe93 100644 --- a/terraform/data.tf +++ b/terraform/data.tf @@ -20,10 +20,31 @@ data "terraform_remote_state" "blc-testnet" { data "terraform_remote_state" "gossip-prod" { backend = "gcs" - workspace = "prod" + workspace = "gossip" config = { bucket = "terraform-bs-source" - prefix = "satellite-api-gossip" + prefix = "satellite-api-reduced-server" } } + +data "terraform_remote_state" "auth-prod" { + backend = "gcs" + workspace = "auth" + + config = { + bucket = "terraform-bs-source" + prefix = "satellite-api-reduced-server" + } +} + +data "terraform_remote_state" "btc-src-prod" { + backend = "gcs" + workspace = "btc_src" + + config = { + bucket = "terraform-bs-source" + prefix = "satellite-api-reduced-server" + } +} + diff --git a/terraform/main.tf b/terraform/main.tf index 72d003a..4da32c5 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -109,6 +109,8 @@ module "lb" { internal_ip_mainnet = module.blc-mainnet.internal_ip internal_ip_testnet = data.terraform_remote_state.blc-testnet.outputs.blc_internal_ip_testnet internal_ip_gossip = data.terraform_remote_state.gossip-prod.outputs.gossip_internal_ip + internal_ip_auth = data.terraform_remote_state.auth-prod.outputs.auth_internal_ip + internal_ip_btc_src = data.terraform_remote_state.btc-src-prod.outputs.btc_src_internal_ip target_pool = length(google_compute_target_pool.lb-pool) > 0 ? google_compute_target_pool.lb-pool[0].self_link : "" health_check = length(google_compute_http_health_check.lb-health) > 0 ? google_compute_http_health_check.lb-health[0].self_link : "" @@ -123,6 +125,8 @@ module "lb" { prom_service_acct = var.prom_service_acct letsencrypt_email = var.letsencrypt_email public_bucket_url = var.public_bucket_url + station1 = var.station1 + station2 = var.station2 } module "tor" { diff --git a/terraform/modules/lb/cloud-init/lb.yaml b/terraform/modules/lb/cloud-init/lb.yaml index bd6b56c..f07b2fd 100644 --- a/terraform/modules/lb/cloud-init/lb.yaml +++ b/terraform/modules/lb/cloud-init/lb.yaml @@ -73,8 +73,8 @@ write_files: # Client cert authenticated endpoints location /order/tx/ { # Allow base stations only - allow 202.161.136.2; - allow 66.203.141.162; + allow ${station1}; + allow ${station2}; deny all; if ($ssl_client_verify != SUCCESS) { @@ -85,8 +85,8 @@ write_files: location /order/rx/ { # Allow base stations only - allow 202.161.136.2; - allow 66.203.141.162; + allow ${station1}; + allow ${station2}; deny all; if ($ssl_client_verify != SUCCESS) { @@ -177,7 +177,7 @@ write_files: proxy_pass http://${gossip_ip}:9292/; } - # Proxy to SSE container + # Proxy to gossip SSE container location /gossip/subscribe/ { chunked_transfer_encoding off; proxy_buffering off; @@ -188,14 +188,15 @@ write_files: proxy_pass http://${gossip_ip}:4500/stream?channels=; } - # Client cert authenticated gossip endpoints + # Only the ground station hosts are authorized to send and modify + # API transmission orders on the gossip server location ~ ^/gossip/order($|/.*)$ { # Allow up to 2MB uploads client_max_body_size 2M; - + # Allow base stations only - allow 202.161.136.2; - allow 66.203.141.162; + allow ${station1}; + allow ${station2}; deny all; if ($ssl_client_verify != SUCCESS) { @@ -203,6 +204,102 @@ write_files: } proxy_pass http://${gossip_ip}:9292/order$1; } + + # Proxy to the authentication server + location /auth/ { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'X-Auth-Token,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; + add_header 'X-XSS-Protection' '1; mode=block' always; + + if ($request_uri ~* "^/auth/?$") + { + return 301 https://$host; + } + + if ($request_method = 'OPTIONS') + { + return 200; + } + + # Restrict all auth server endpoints to the ground station hosts + # authenticated via client-side SSL cert + allow ${station1}; + allow ${station2}; + deny all; + + if ($ssl_client_verify != SUCCESS) { + return 403; + } + + proxy_pass http://${auth_ip}:9292/; + } + + # Proxy to auth server's SSE container + location /auth/subscribe/ { + chunked_transfer_encoding off; + proxy_buffering off; + proxy_request_buffering off; + proxy_cache off; + proxy_http_version 1.1; + + allow ${station1}; + allow ${station2}; + deny all; + + if ($ssl_client_verify != SUCCESS) { + return 403; + } + + proxy_pass http://${auth_ip}:4500/stream?channels=; + } + + # Proxy to the Bitcoin source code transmission server + location /btc-src/ { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'X-Auth-Token,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; + add_header 'X-XSS-Protection' '1; mode=block' always; + + if ($request_uri ~* "^/btc-src/?$") + { + return 301 https://$host; + } + + if ($request_method = 'OPTIONS') + { + return 200; + } + + proxy_pass http://${btc_src_ip}:9292/; + } + + # Proxy to btc-src's SSE container + location /btc-src/subscribe/ { + chunked_transfer_encoding off; + proxy_buffering off; + proxy_request_buffering off; + proxy_cache off; + proxy_http_version 1.1; + + proxy_pass http://${btc_src_ip}:4500/stream?channels=; + } + + # Only the ground station hosts are authorized to send and modify + # API transmission orders on the btc-src server + location ~ ^/btc-src/order($|/.*)$ { + # Allow up to 2MB uploads + client_max_body_size 2M; + + allow ${station1}; + allow ${station2}; + deny all; + + if ($ssl_client_verify != SUCCESS) { + return 403; + } + proxy_pass http://${btc_src_ip}:9292/order$1; + } } - path: /home/bs/index.html diff --git a/terraform/modules/lb/data.tf b/terraform/modules/lb/data.tf index ac96295..d803d41 100644 --- a/terraform/modules/lb/data.tf +++ b/terraform/modules/lb/data.tf @@ -11,6 +11,8 @@ data "template_file" "satapi-lb" { mainnet_ip = var.internal_ip_mainnet testnet_ip = var.internal_ip_testnet gossip_ip = var.internal_ip_gossip + auth_ip = var.internal_ip_auth + btc_src_ip = var.internal_ip_btc_src certbot_docker = var.certbot_docker node_exporter_docker = var.node_exporter_docker host = var.host @@ -18,6 +20,8 @@ data "template_file" "satapi-lb" { public_bucket = replace(google_storage_bucket.satapi-lb-public[count.index].url, "gs://", "") private_bucket = replace(google_storage_bucket.satapi-lb-private[count.index].url, "gs://", "") letsencrypt_email = var.letsencrypt_email + station1 = var.station1 + station2 = var.station2 } } diff --git a/terraform/modules/lb/variables.tf b/terraform/modules/lb/variables.tf index 5f22ab2..0ba16ff 100644 --- a/terraform/modules/lb/variables.tf +++ b/terraform/modules/lb/variables.tf @@ -59,6 +59,14 @@ variable "internal_ip_gossip" { type = string } +variable "internal_ip_auth" { + type = string +} + +variable "internal_ip_btc_src" { + type = string +} + variable "health_check" { type = string } @@ -71,6 +79,14 @@ variable "target_pool" { type = string } +variable "station1" { + type = string +} + +variable "station2" { + type = string +} + variable "node_exporter_docker" { type = string } diff --git a/terraform/variables.tf b/terraform/variables.tf index 80ab5a1..59357f2 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -143,6 +143,16 @@ variable "internal_ip_gossip" { default = "" } +variable "internal_ip_auth" { + type = string + default = "" +} + +variable "internal_ip_btc_src" { + type = string + default = "" +} + variable "health_check" { type = string default = "" @@ -194,6 +204,16 @@ variable "letsencrypt_email" { default = "" } +variable "station1" { + type = string + default = "" +} + +variable "station2" { + type = string + default = "" +} + variable "ionosphere_docker" { type = string default = ""