LayerX エンジニアブログ

LayerX の エンジニアブログです。

ガバナンスとアジリティを両立する金融システムのTerraform基盤設計

本記事は LayerX Tech Advent Calender 2022の12/15分の記事です。


自己紹介

LayerXでエンジニアをしている Etaro ( @etaroid )です。

現在は、三井物産デジタル・アセットマネジメントにて デジタル証券で資産運用ができる個人向け投資サービス「ALTERNA(オルタナ)」の新規開発を行っています。

以前は同社内で法人向け投資サービスのフロントエンド、バックエンド開発などを行っていました。

個人向け投資サービス「ALTERNA (オルタナ)」では、インフラの開発をメインで担当しております。

alterna-z.com

MDMとは

三井物産デジタル・アセットマネジメント(以下、MDM)は、スタートアップであるLayerXと、三井物産、SMBC日興証券、三井住友信託銀行などの大企業との合弁会社としてスタートしたジョイントベンチャーです。

www.fastgrow.jp

大企業の信頼と実績を支えるガバナンスを守りつつ、スタートアップのモダンな技術と高いアジリティを両立することがMDMの最大の強み・面白みであり、それを少しでも高いレベルで実現することに日々取り組んでいます。

本記事では そんなMDMがAM会社・証券会社としての金融システムを開発・運用するにあたっての基盤となるインフラストラクチャの部分をどのように設計・実装しているのかをご紹介したいと思います。

金融システムのインフラに求められる要件

金商業者のシステムにおいては、「開発と運用の分離」が強く求められます。

FISC(金融情報システムセンター)の「金融機関等コンピュータシステムの安全対策基準・解説書 第9版」にも、以下のような記載があります。

コンピュータシステムに係わる業務を円滑かつ適正に運営するとともに、不正を防止するため、 業務範囲並びに責任及び権限を明確にし、相互牽制体制を整備すること。

...

(1) 業務組織を分離・分担する。
プログラムの作成、入力データの作成、コンピュータシステムの運転、ライブラリ管理 等を分担することにより、相互牽制を図る。

ネットワークや権限、データストアなどシステムの基盤となるインフラは、もちろん厳しくガバナンスを効かせる必要があります。

また、お客様が直接利用するサービス(Front System、以下FS)に加えて、社内向けの管理画面(Back System、以下BS)があり、FSとBSで共通して利用するリソース(以下、Common)も存在します。

このような複数のシステムコンポーネントの管理と、ガバナンスのための権限分離をどのように実現するか。それでいてアジリティを低下させず、爆速開発を実現するかが重要になります。

Terraformワーキングディレクトリの設計

Terraformのワーキングディレクトリとは、plan や applyを実行する単位となるディレクトリを指します。

Terraformのワーキングディレクトリ設計には「全てのリソースを1つのワーキングディレクトリにすることでシンプルさを保つ」というものから「リソースを種別ごとに細かく分けてそれぞれをワーキングディレクトリとして分離する」というものまで様々な流派があります。

弊社では、以下の2つの基準で設計を行いました。

デプロイ単位での分離

Terraformには変更予定の差分をチェックするplanやその差分を適用するapplyといった機能がありますが、実際には意図しない差分が出たり、planは通ったがapplyは通らないということが起こることがあります。

そのため、デプロイ単位でワーキングディレクトリを物理的に分けてしまうことで影響範囲を限定することが重要と考えています。

弊社の場合は、前述した

  • FS
  • BS
  • Common(FS / BS共通で利用するリソース)

の3つにデプロイ単位を分割しました。

こうすることでBSのインフラリソースだけを更新したいが、FS側のインフラに差分が出てユーザー影響が出てしまうことを気にしなくてはならないといった状況を回避することができます。

変更頻度と重要度によって権限を分離

弊社では前述の通り、ガバナンスを効かせるために開発と運用の2つにインフラストラクチャの管理権限を分離する必要があります。

サービスをリリースしたのち、

  • 開発チームが、前線で機能改善や新機能追加を行う際に頻繁に更新してもよいインフラ部分
  • 運用チームが、厳格に保守する必要があり、頻繁に変更されるべきではない基盤インフラ部分

の2つにワーキングディレクトリを分離する方針としました。

具体的には、

  • アプリケーション開発で利用するS3、Cloudfront、ECS、ALB、EventBridgeなどは開発チームの権限下でアジリティ高く変更できる
  • ネットワークやRouting、インフラで利用するS3、DB、IAM、KMS、Secrets Manager、CICD、ログや監視周りのリソースなどは運用チームの権限でしか変更できない

といった分類です。

実際のディレクトリ構成は、以下のようになりました。

権限でGitリポジトリを分離、さらに各リポジトリ内のデプロイ単位でワーキングディレクトリを分離し、計6つのワーキングディレクトリが存在する形になっています。

alterna Repository (monorepo) // 開発チームで管理するリポジトリ
├──api
├──webapp
├──...
├──infra
    ├── common // FS / BS共通で利用するリソース
    │   ├── terraform
    │       ├── ...tf files
    ├── fs // FSで利用するリソース
    │   ├── terraform
    │       ├── ...tf files
    ├── bs // BSで利用するリソース
        ├── terraform
            ├── ...tf files
    

alterna-operation Repository // 運用チームで管理するリポジトリ
├── common // FS / BS共通で利用するリソース
│   ├── terraform
│       ├── ...tf files
├── fs // FSで利用するリソース
│   ├── terraform
│       ├── ...tf files
├── bs // BSで利用するリソース
    ├── terraform
        ├── ...tf files

この設計の嬉しさ

単純にガバナンス一辺倒にしてしまうと「infraは全て運用チーム管理」となってしまいそうなところを、このようなワーキングディレクトリの適切な分離を行うことで、ガバナンスを守りつつ、開発のアジリティを高めることができます。

具体的には、新機能追加に伴って「定期処理を行うバッチを1つずつ追加する」「新しく画像を配信するためにS3とCloudfrontを変更する」などのインフラ変更が必要な場合に、

  • 開発チームだけで素早く実装が可能
  • applyの際にも変更の影響範囲が絞られているため、安心して更新ができる

といったことが実現できるイメージです。

複数ワーキングディレクトリの管理

もちろんワーキングディレクトリが複数に分かれるということは、

  • 重複するコードが増えていってしまう
  • ワーキングディレクトリ間の依存関係を考慮する必要がある

という問題はあります。

resourceのコードはmoduleを利用するなどで対応できますし、config周りの重複とワーキングディレクトリ間の依存関係はTerragruntというツールで対応する事ができます。

terragrunt.gruntwork.io

詳しくは公式ドキュメントに譲りますが、以下に利用例を紹介します。

provider / backend config をDRYに管理する

Terraformのconfig関連の記述であるproviderやbackendなどの設定は全てのワーキングディレクトリで同じようなものになることが多いにも関わらず、各ワーキングディレクトリに記述しなくてはなりません。

alterna Repository (monorepo)
├──infra
    ├── common
    │   ├── terraform
    │       ├── provider.tf
    │       ├── terraform.tf
    │       ├── backend.tf
    ├── fs
    │   ├── terraform
    │       ├── ... // ここにも
    ├── bs
        ├── terraform
            ├── ... // ここにも
    

alterna-operation Repository
├── common
│   ├── terraform
│           ├── provider.tf
│           ├── terraform.tf
│           ├── backend.tf
├── fs
│   ├── terraform
│           ├── ... // ここにも
├── bs
    ├── terraform
            ├── ... // ここにも

そこで、Terragruntを利用することで設定の共通化ができます。

管理する階層の一番上に親となるterragrunt.hcl (今回は root-terragrunt.hclという名前)を作成し、そこに記載された設定を子ディレクトリにあるterragrunt.hclで読み込むイメージです。

具体的には以下のように記述します。 各子設定ファイルで親の設定をoverrideすることもできます。

// root-terragrunt.hcl (親設定ファイル)

generate "terraform" {
  path      = "terraform.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_version = "~> 1.3.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.22.0"
    }
  }
}
EOF
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
  region = "ap-northeast-1"
}
provider "aws" {
  region = "us-east-1"
  alias  = "north_virginia"
}
EOF
}

remote_state {
  backend = "s3"
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
  config = {
    bucket  = "bucket-name-for-tfstate"
    region  = "ap-northeast-1"
    key     = "override-by-child-hcl"
    encrypt = true
  }
}
// terragrunt.hcl (各ディレクトリに存在する子設定ファイル)

include "root" {
  path           = find_in_parent_folders("root-terragrunt.hcl")
  merge_strategy = "deep"
}

remote_state {
  config = {
    key = "override-name.tfstate"
  }
}

ワーキングディレクトリ間の依存関係を管理する

ワーキングディレクトリ間の依存関係もterragrunt.hcl に記述することで表現できます。 terragrunt run-allコマンドでのplanやapplyの実行時に実行順を依存関係に基づいて調整してくれます。

BSのリソースがCommonに依存しているケースを考えると、具体的には以下のように記述します。

// bs/terragrunt.hcl

include "root" {
  path = find_in_parent_folders()
}

dependencies = {
  paths = ["../common"]
}

以上が、ガバナンスとアジリティを両立するために取り組んでいるTerraform基盤設計の工夫のご紹介でした。

MDMは、このような創意工夫を日々積み重ねることで、ガバナンスとアジリティを両立できることを証明し続ける業界のモデルケースになっていきたいと考えています!

ALTERNA、事前登録受付中!

デジタル証券で資産運用ができる個人向けサービス「ALTERNA(オルタナ)」は近日リリース予定です。

現在、リリースに先駆けて 事前登録受付中 なので是非以下のLinkまたはQRコードからご登録をお願いします!

alterna-z.com

ALTERNA事前登録ページQRコード
ALTERNA 事前登録ページ

共に働く仲間を募集中!

AM・証券会社の金融システムを創意工夫をしながら作っていく のに興味がある方を募集中ですので、少しでも興味を持っていただけた方がいましたら、是非以下からご連絡下さい!

jobs.layerx.co.jp