diff options
Diffstat (limited to 'corp/ops')
-rw-r--r-- | corp/ops/.envrc | 4 | ||||
-rw-r--r-- | corp/ops/.gitignore | 4 | ||||
-rw-r--r-- | corp/ops/default.nix | 46 | ||||
-rw-r--r-- | corp/ops/modules/.skip-tree | 1 | ||||
-rw-r--r-- | corp/ops/modules/yandex-cloud.nix | 79 | ||||
-rw-r--r-- | corp/ops/yandex/creds.fish | 5 | ||||
-rw-r--r-- | corp/ops/yandex/encrypted-state-secret.key | bin | 0 -> 121 bytes | |||
-rw-r--r-- | corp/ops/yandex/main.tf | 70 | ||||
-rw-r--r-- | corp/ops/yandex/rih.tf | 69 |
9 files changed, 278 insertions, 0 deletions
diff --git a/corp/ops/.envrc b/corp/ops/.envrc new file mode 100644 index 000000000000..26049cf426a4 --- /dev/null +++ b/corp/ops/.envrc @@ -0,0 +1,4 @@ +out=$(nix-build ../.. -A corp.ops.deps --out-link ../../.gcroots/corp-deps) +PATH_add "$out/bin" + +watch_file default.nix diff --git a/corp/ops/.gitignore b/corp/ops/.gitignore new file mode 100644 index 000000000000..5def054d764c --- /dev/null +++ b/corp/ops/.gitignore @@ -0,0 +1,4 @@ +.terraform +.terraform.lock.hcl +terraform.tfstate +terraform.tfstate.backup diff --git a/corp/ops/default.nix b/corp/ops/default.nix new file mode 100644 index 000000000000..59d63bd5101b --- /dev/null +++ b/corp/ops/default.nix @@ -0,0 +1,46 @@ +{ depot, lib, pkgs, ... }: + +depot.nix.readTree.drvTargets rec { + # Provide a Terraform wrapper with Yandex Cloud support. + terraform = pkgs.terraform.withPlugins (p: [ + p.yandex + ]); + + validate = depot.tools.checks.validateTerraform { + inherit terraform; + name = "corp"; + src = lib.cleanSource ./.; + }; + + # Yandex Cloud CLI + yc-cli = pkgs.stdenv.mkDerivation rec { + pname = "yc-cli"; + version = "0.106.0"; + + src = pkgs.fetchurl { + url = "https://storage.yandexcloud.net/yandexcloud-yc/release/${version}/linux/amd64/yc"; + sha256 = "sha256:1f7fq9rlihz91ld1vdjj9vq9ssq1ls031jin4zisxv75rcdpslh3"; + }; + + phases = [ "installPhase" ]; + installPhase = "install -D $src $out/bin/yc"; + }; + + deps = depot.tools.depot-deps.overrideDeps { + tf-yandex = { + attr = "corp.ops.terraform"; + cmd = "terraform"; + }; + + yc.attr = "corp.ops.yc-cli"; + }; + + # Base image for Yandex VMs. + yandex-base-image = (depot.third_party.nixos { + configuration = { ... }: { + imports = [ + (depot.path.origSrc + ("/corp/ops/modules/yandex-cloud.nix")) + ]; + }; + }).config.system.build.yandexCloudImage; +} diff --git a/corp/ops/modules/.skip-tree b/corp/ops/modules/.skip-tree new file mode 100644 index 000000000000..a6f528167f00 --- /dev/null +++ b/corp/ops/modules/.skip-tree @@ -0,0 +1 @@ +Only NixOS modules here. diff --git a/corp/ops/modules/yandex-cloud.nix b/corp/ops/modules/yandex-cloud.nix new file mode 100644 index 000000000000..cca81bc0ca5e --- /dev/null +++ b/corp/ops/modules/yandex-cloud.nix @@ -0,0 +1,79 @@ +# Profile for virtual machines on Yandex Cloud, intended for disk +# images. +# +# https://cloud.yandex.com/en/docs/compute/operations/image-create/custom-image +# +# TODO(tazjin): Upstream to nixpkgs once it works well. +{ config, lib, pkgs, modulesPath, ... }: + +let + cfg = config.virtualisation.yandexCloud; + + # Kernel modules required for interacting with the hypervisor. These + # must be available during stage 1 boot and during normal operation, + # as disks and network do not work without them. + modules = [ + "virtio-net" + "virtio-blk" + "virtio-pci" + "virtiofs" + ]; +in +{ + imports = [ + "${modulesPath}/profiles/headless.nix" + ]; + + options = { + virtualisation.yandexCloud.rootPartitionUuid = with lib; mkOption { + type = types.str; + default = "C55A5EE2-E5FA-485C-B3AE-CC928429AB6B"; + + description = '' + UUID to use for the root partition of the disk image. Yandex + Cloud requires that root partitions are mounted by UUID. + + Most users do not need to set this to a non-default value. + ''; + }; + }; + + config = { + fileSystems."/" = { + device = "/dev/disk/by-uuid/${lib.toLower cfg.rootPartitionUuid}"; + fsType = "ext4"; + autoResize = true; + }; + + boot = { + loader.grub.device = "/dev/vda"; + + initrd.kernelModules = modules; + kernelModules = modules; + kernelParams = [ + # Enable support for the serial console + "console=ttyS0" + ]; + + growPartition = true; + }; + + environment.etc.securetty = { + text = "ttyS0"; + mode = "0644"; + }; + + systemd.services."serial-getty@ttyS0".enable = true; + + services.openssh.enable = true; + services.cloud-init.enable = true; + + system.build.yandexCloudImage = import (pkgs.path + "/nixos/lib/make-disk-image.nix") { + inherit lib config pkgs; + additionalSpace = "128M"; + format = "qcow2"; + partitionTableType = "legacy+gpt"; + rootGPUID = cfg.rootPartitionUuid; + }; + }; +} diff --git a/corp/ops/yandex/creds.fish b/corp/ops/yandex/creds.fish new file mode 100644 index 000000000000..2985b2880864 --- /dev/null +++ b/corp/ops/yandex/creds.fish @@ -0,0 +1,5 @@ +export YC_TOKEN=(yc iam create-token) +export YC_CLOUD_ID=(yc config get cloud-id) +export YC_FOLDER_ID=(yc config get folder-id) +export AWS_ACCESS_KEY_ID="YCAJE6eRLY8Az-9kveNRtz4sh" +export AWS_SECRET_ACCESS_KEY=(yc kms symmetric-crypto decrypt --name tvl-credentials --cloud-id b1ggu5m1btue982app12 --folder-name default --ciphertext-file encrypted-state-secret.key --plaintext-file /dev/stdout | head -n1) diff --git a/corp/ops/yandex/encrypted-state-secret.key b/corp/ops/yandex/encrypted-state-secret.key new file mode 100644 index 000000000000..0d07158f2f01 --- /dev/null +++ b/corp/ops/yandex/encrypted-state-secret.key Binary files differdiff --git a/corp/ops/yandex/main.tf b/corp/ops/yandex/main.tf new file mode 100644 index 000000000000..cd8fa6e4cc67 --- /dev/null +++ b/corp/ops/yandex/main.tf @@ -0,0 +1,70 @@ +# Terraform configuration for TVL corp infrastructure (on Yandex +# Cloud). + +terraform { + required_providers { + yandex = { + source = "yandex-cloud/yandex" + } + } + + # Credentials need to be sourced from creds.fish + backend "s3" { + endpoint = "storage.yandexcloud.net" + bucket = "su-tvl-terraform-state" + region = "ru-central1" + key = "corp/ops/terraform.tfstate" + + skip_region_validation = true + skip_credentials_validation = true + } +} + +provider "yandex" { + zone = "ru-central1-b" +} + +locals { + tvl_cloud_id = "b1ggu5m1btue982app12" + tvl_folder_id = "b1gmbeqt9o5kbl7rclln" + rih_cloud_id = "b1glccvcqggi2ruibgvt" + rih_folder_id = "b1gsavcrsjn059d1sbh9" +} + +# Storage state bucket configuration + +resource "yandex_iam_service_account" "tf_state_sa" { + folder_id = local.tvl_folder_id + name = "terraform-state" +} + +resource "yandex_resourcemanager_folder_iam_member" "tf_state_sa_storage" { + folder_id = local.tvl_folder_id + role = "storage.editor" + member = "serviceAccount:${yandex_iam_service_account.tf_state_sa.id}" +} + +resource "yandex_iam_service_account_static_access_key" "tf_state_sa_key" { + service_account_id = yandex_iam_service_account.tf_state_sa.id + description = "Static access key for Terraform state" +} + +resource "yandex_storage_bucket" "tf_state" { + access_key = yandex_iam_service_account_static_access_key.tf_state_sa_key.access_key + secret_key = yandex_iam_service_account_static_access_key.tf_state_sa_key.secret_key + bucket = "su-tvl-terraform-state" +} + +# Secret management configuration + +resource "yandex_kms_symmetric_key" "tvl_credentials_key" { + name = "tvl-credentials" + folder_id = local.tvl_folder_id + default_algorithm = "AES_256" + rotation_period = "2160h" # 90 days +} + +resource "yandex_kms_secret_ciphertext" "tf_state_key" { + key_id = yandex_kms_symmetric_key.tvl_credentials_key.id + plaintext = yandex_iam_service_account_static_access_key.tf_state_sa_key.secret_key +} diff --git a/corp/ops/yandex/rih.tf b/corp/ops/yandex/rih.tf new file mode 100644 index 000000000000..de51ad738e80 --- /dev/null +++ b/corp/ops/yandex/rih.tf @@ -0,0 +1,69 @@ +# Deployment configuration for russiaishiring.com +# +# The frontend of the page is served from a storage bucket, the +# backend runs in a container. + +resource "yandex_dns_zone" "russiaishiring_com" { + name = "russiaishiring-com" + zone = "russiaishiring.com." + public = true + folder_id = local.rih_folder_id +} + +resource "yandex_iam_service_account" "rih_storage_sa" { + name = "rih-storage-sa" + folder_id = local.rih_folder_id +} + +resource "yandex_resourcemanager_folder_iam_member" "rih_sa_storage_editor" { + folder_id = local.rih_folder_id + role = "storage.editor" + member = "serviceAccount:${yandex_iam_service_account.rih_storage_sa.id}" +} + +resource "yandex_iam_service_account_static_access_key" "rih_sa_static_key" { + service_account_id = yandex_iam_service_account.rih_storage_sa.id + description = "RIH bucket access key" +} + +resource "yandex_storage_bucket" "rih_storage_bucket" { + access_key = yandex_iam_service_account_static_access_key.rih_sa_static_key.access_key + secret_key = yandex_iam_service_account_static_access_key.rih_sa_static_key.secret_key + bucket = "russiaishiring.com" + folder_id = local.rih_folder_id + acl = "public-read" + + https { + certificate_id = yandex_cm_certificate.russiaishiring_com.id + } + + website { + index_document = "index.html" + } +} + +resource "yandex_cm_certificate" "russiaishiring_com" { + folder_id = local.rih_folder_id + name = "russiaishiring-com" + domains = ["russiaishiring.com"] + + managed { + challenge_type = "DNS_CNAME" + } +} + +resource "yandex_dns_recordset" "acme_russiaishiring_com" { + zone_id = yandex_dns_zone.russiaishiring_com.id + name = yandex_cm_certificate.russiaishiring_com.challenges[0].dns_name + type = yandex_cm_certificate.russiaishiring_com.challenges[0].dns_type + data = [yandex_cm_certificate.russiaishiring_com.challenges[0].dns_value] + ttl = 60 +} + +resource "yandex_dns_recordset" "aname_russiaishiring_com" { + zone_id = yandex_dns_zone.russiaishiring_com.id + name = "russiaishiring.com." + type = "ANAME" + data = ["russiaishiring.com.website.yandexcloud.net"] + ttl = 600 +} |