blog

DeNAのエンジニアが考えていることや、担当しているサービスについて情報発信しています

2022.09.30 技術記事

Terraformで AWS WorkSpaces (SimpleAD) を構築する際にユーザー作成で工夫した話 [DeNA インフラ SRE]

by lin.cui

#インフラ #sre #infrastructure #terraform #aws #windows #infosys #AmazonWorkSpaces #cost-optimization #public-cloud #IaC

はじめに

こんにちは。2022年1月に入社しましたIT本部IT基盤部第三グループの崔です。

ChromebookとAmazon WorkSpacesを使った業務環境の構築 社内システムのクラウド移行 で記載した内容のように、社内ではWorkspacesを数百台を使用しています。 これらの Workspaces環境の構築や維持管理をTerraformを使って効率化することを進めています。
本記事ではWorkspaces環境で使うSimple ADのユーザ作成の部分で工夫したことを紹介したいと思います。

Simple ADのユーザー作成について

AWSのコンソール画面ではステップに従って構築できるのですが、terraformではこの作業をうまく記述できませんでした。

AWSのコンソール上では

AWSコンソール上ではWorkspaces作成画面でユーザー作成・一覧検索・選択が可能です。
Workspaces構築画面ではユーザー作成が必須のステップになっているので、特に気にすることはなく、ポチポチクリックするだけです。

Amazon Workspaces Create Simple AD User

Terraformでは

Terraform Workspaces Resourceでuser_name で指定するユーザ名は既に存在していることが必須になっていて、このリソースで作成するものではないのです。
しかしながら、terraformのAWS Provider(本稿執筆時点では4.30.0です)では、Simple ADにユーザアカウントを作成する機能がまだ実装されていないようなのです。

resource "aws_workspaces_workspace" "example" {
  directory_id = aws_workspaces_directory.example.id
  bundle_id    = data.aws_workspaces_bundle.value_windows_10.id
  user_name    = "john.doe"  既に存在しているユーザ名を指定する必要がある
  ・・・
}

What will do?

terraformのaws providerでユーザを作ることができないが、何か他の方はないだろうか?
Google先生に尋ねたところ、以下の方法を教えていただきました。

  1. Terraform でaws cliを呼び出せばよさそう。
  2. aws cli workdocs ではユーザを作ることができる。
  3. Simple ADでユーザアカウントをaws cliを使って作るには、workdocs を予め有効化しておく必要がある。

これを組み合わせれば、うまくいきそうです。

TerraformとAWS Cliの組み合わせでSimple ADのユーザー作成

Googleから収集した情報でサンプルコードを作成しました。

simplead_directory.tf


data "aws_region" "current" {}

resource "random_id" "alias_unique" {
  byte_length = 8
}

// Simple AD Directory作成
resource "aws_directory_service_directory" "simple_ad" {
  type     = local.directory_type_name
  size     = local.directory_size
  name     = local.dns_name
  password = local.directory_password
  alias    = random_id.alias_unique.hex

  vpc_settings {
    vpc_id     = local.vpc_id
    subnet_ids = local.subnet_ids
  }

  depends_on = [
    random_id.alias_unique
  ]
}

// SimpleADのworkdocs 有効化
resource "null_resource" "workdocs" {
  provisioner "local-exec" {
    command = "aws workspaces register-workspace-directory --directory-id ${aws_directory_service_directory.simple_ad[0].id} --enable-work-docs --region ${data.aws_region.current.name} --profile ${local.aws_profile_name}"
  }

  depends_on = [
    aws_directory_service_directory.simple_ad
  ]
}

ad_directory.tf

// SimpleADの詳細設定
resource "aws_workspaces_directory" "directory" {
  directory_id = local.directory_id
  subnet_ids = local.subnet_ids
  ip_group_ids = local.directory_ip_group
  self_service_permissions {
    change_compute_type  = local.directory_self_service_permissions.change_compute_type
    increase_volume_size = local.directory_self_service_permissions.increase_volume_size
    rebuild_workspace    = local.directory_self_service_permissions.rebuild_workspace
    restart_workspace    = local.directory_self_service_permissions.restart_workspace
    switch_running_mode  = local.directory_self_service_permissions.switch_running_mode
  }
  workspace_access_properties {
    device_type_android    = local.directory_access_properties.device_type_android
    device_type_chromeos   = local.directory_access_properties.device_type_chromeos
    device_type_ios        = local.directory_access_properties.device_type_ios
    device_type_linux      = local.directory_access_properties.device_type_linux
    device_type_osx        = local.directory_access_properties.device_type_osx
    device_type_web        = local.directory_access_properties.device_type_web
    device_type_windows    = local.directory_access_properties.device_type_windows
    device_type_zeroclient = local.directory_access_properties.device_type_zeroclient
  }
  workspace_creation_properties {
    // ディレクトリの詳細 ーセキュリティグループ
    custom_security_group_id            = local.directory_security_group.ad_security_group
    default_ou                          = local.directory_creation_properties.default_ou
    enable_internet_access              = local.directory_creation_properties.enable_internet_access
    enable_maintenance_mode             = local.directory_creation_properties.enable_maintenance_mode
    user_enabled_as_local_administrator = local.directory_creation_properties.user_enabled_as_local_administrator
  }

  lifecycle {
    ignore_changes = [subnet_ids]
  }

  depends_on = [
    null_resource.workdocs
  ]
}

create_user.tf

data "aws_region" "current" {}
// SimpleADのユーザー作成
resource "null_resource" "createuser" {
  for_each = { for i in local.ad_workspaces_users : i.user_name => i } : {}
  provisioner "local-exec" {
    command    = "aws workdocs create-user --organization-id ${local.directory_id} --username ${each.value.user_name} --email-address ${each.value.email_address} --given-name ${each.value.given_name} --surname ${each.value.surname} --password ${each.value.password} --region ${data.aws_region.current.name} --profile ${local.aws_profile_name}"
  }
}

workspace.tf

resource "aws_workspaces_workspace" "workspace" {
  for_each     = { for i in local.ad_workspaces_users : i.user_name => i }
  directory_id = local.directory_id
  bundle_id    = each.value.base_bundle_image_id
  user_name    = each.value.user_name

  root_volume_encryption_enabled = true
  user_volume_encryption_enabled = true

  volume_encryption_key = data.aws_kms_key.by_alias.key_id
  workspace_properties {
    compute_type_name                         = each.value.compute_type_name
    user_volume_size_gib                      = each.value.user_volume_size_gib
    root_volume_size_gib                      = each.value.root_volume_size_gib
    running_mode                              = each.value.running_mode
    running_mode_auto_stop_timeout_in_minutes = each.value.running_mode == "ALWAYS_ON" ? 0 : 60
  }

  timeouts {
    create = "2h"
    update = "2h"
    delete = "2h"
  }

  lifecycle {
    prevent_destroy = true
    ignore_changes = [
      volume_encryption_key,
      bundle_id,
      directory_id
    ]
  }

  depends_on = [
    null_resource.createuser
  ]
}

variables.tf

locals {
  ad_workspaces_users = [
      {
        base_bundle_image_id = "wsb-gk1wpk43z"
        user_name            = "lin.cui"
        email_address        = "lin.cui@dena.com"
        given_name           = "lin"
        surname              = "cui"
        password             = "Password1234"
        compute_type_name = "VALUE"
        root_volume_size_gib = 80
        user_volume_size_gib = 10
        //AUTO_STOP ALWAYS_ON
        running_mode = "AUTO_STOP"
      },
      ・・・
  ]
  ...
}
実行!!!

おおー問題なく、Workspacesまで作成されました。
これでterraformで、Simple ADのユーザも含めてWorkspaces環境を記述することができました。

おわりに

TerraformはAWS Workspacesの構築に対して優しくないので、今後はいろいろ機能を追加してほしいです。
今回紹介した例を使うことでお役に立てば幸いです。
最後までお読みいただき、ありがとうございました。

関連記事:

最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。

recruit

DeNAでは、失敗を恐れず常に挑戦し続けるエンジニアを募集しています。