マルチリポジトリの共通PythonパッケージをAWS CodeArtifactでいい感じに配布する設計をまとめてみる

マルチリポジトリの共通PythonパッケージをAWS CodeArtifactでいい感じに配布する設計をまとめてみる

複数のサービスを別々のリポジトリで開発する際、共通Pythonパッケージの共有をどう実現するか。コピー配置の破綻、Submoduleの手間、monorepoの過去の失敗を経て、AWS CodeArtifactをプライベートレジストリとした「いい感じに」管理する設計を紹介します。
2026.09.09

はじめに

データ事業本部のkobayashiです。

複数のサービスを別々のリポジトリで開発していると、「どのサービスからも使う共通コード」をどう共有するかという問題に必ずぶつかります。ロガーの設定、共通のデータモデル、暗号ユーティリティなどがその典型です。

もっとも手軽なのは各リポジトリにコピーを置くことですが、この運用ですと片方のリポジトリにだけ修正が入り、コピー同士が少しずつ乖離していきます。実際に、運用しているプロジェクトで、最も乖離が少ないはずの共通ロガーですら 「片方のリポジトリにだけセキュリティ修正が存在する」 状態が発生していました。

そこで今回は、マルチリポジトリ構成の共通 Python パッケージを AWS CodeArtifact をプライベートレジストリとして配布する 方式で「いい感じに」管理する設計を、実プロジェクトの設計・意思決定記録を一般化する形でまとめます。単に「CodeArtifactにpublishする」だけでなく、ローカル開発体験を犠牲にしない3層モデルクロスアカウント read の権限設計publish 経路のハードニングバージョニングの罠回避 まで含めて、実運用で必要になる点を一通り扱います。

なお本記事の Poetry まわりの記述は Poetry 2.3.4 で確認したものです。priority = "explicit" の効き方や allow-prereleases の扱い、poetry update のオプションはバージョンによって変わるため、お使いの版で挙動をご確認ください。

なぜレジストリ配布なのか(Submodule / Subtree / monorepo との比較)

共通コードをマルチリポジトリで共有する方式にはいくつか選択肢があります。当初は「Git Submodule で進める」という方針でしたが、以下の軸で再検討した結果、レジストリ配布に切り替えました。

観点 Git Submodule Git Subtree monorepo プライベートレジストリ
バージョン管理 コミットハッシュ(semver不可) コピーごとに発散 内部参照 semverで明示管理
推移的依存の解決 相対パス構造の維持が必要 同左 ツール依存 pip / Poetry が自動解決(※内部パッケージ同士は後述の注意あり)
更新の伝搬 全親リポでポインタ更新コミット 全リポで subtree pull 即時 Renovate が自動PR
親リポPRでの可視性 ハッシュ差分1行のみ 履歴が混ざる lockファイル差分 + リリースノート
段階展開(リポごとに別バージョン) 困難 ほぼ不可能 不可 容易(バージョン範囲指定)

それぞれを採用しなかった理由は次のとおりです。

  • Submodule は「更新のやり忘れを減らしたい」というゴールと逆の性質を持ちます。共有リポに1コミット入るたびに全親リポでポインタ更新コミットが必要になり、更新忘れが構造的に発生します。さらに親リポのPRにはハッシュ差分1行しか出ず、レビューで「何が変わったか」が見えません
  • Subtree はコピー乖離問題そのものを解決しません
  • workspace(uv workspace 等) はモノレポ内専用で、マルチリポには適用できません
  • monorepo は魅力的な選択肢ですが、このプロジェクトでは「サービスごとのリリースタイミングの独立性」を保つために 意図的にマルチリポへ分割した経緯 があり、再びモノレポに戻すとサービス間のリリース調整負担という過去に解いた問題が再発します

対して レジストリ配布 は、semver による明示的バージョン管理・推移的依存の自動解決・Renovate との連携(やり忘れ防止)をすべて満たします。唯一の弱点である「ローカル開発体験」は、後述の3層モデルで解決します。

全体構成

今回設計した配布方式を図にすると次のようになります。

ポイントは以下の3点です。

  1. 共通コードは1つのリポジトリ(shared-packages)に集約し、そこが唯一の source of truth になる
  2. CodeArtifact には内部パッケージだけを置く(public 依存はプロキシしない)
  3. publish は CI から OIDC ロールで厳格に、read は消費アカウント全体に緩く と、書き込みと読み取りで権限の絞り方を変える

以降で各要素を掘り下げます。

CodeArtifact の構成

レジストリに CodeArtifact を選ぶ理由

  • 認証が IAM ベースで、既存の AWS 基盤・GitHub Actions OIDC と整合する
  • クロスアカウントのリソースベースポリシーで、複数の消費アカウントへの read 許可を宣言的に管理できる
  • Python(PyPI 形式)と npm を同じ domain / repository に同居させられる(本記事は Python に絞って書きますが、実際には npm パッケージも同居させています。ただしプレリリース運用だけは Python の allow-prereleases ではなく npm の dist-tag(dev / latest)で表現する必要があり、ここだけ方式が非対称になります)

内部パッケージのみを対象にする

CodeArtifact は「public 依存(PyPI)も upstream 経由で全部集約する」構成も取れますが、今回は 内部パッケージだけを CodeArtifact に置き、public 依存は従来どおり PyPI から直接解決する 構成を採用しました。

domain: myorg
└── internal        # 共有パッケージの publish 先(external connection なし)

理由は dependency confusion 対策 になります。内部パッケージと同名のパッケージが public レジストリに存在すると、そちらを誤って取得してしまう攻撃・事故がありえます。これは「内部パッケージは CodeArtifact からのみ解決する」よう明示すれば防げます。

Poetry では priority = "explicit" を使い、source を明示指定した内部依存だけが CodeArtifact を見るようにします。public 依存は PyPI から解決され、影響範囲が最小になります。

public を全プロキシする構成は監査の一元化・公開レジストリ障害耐性という利点がありますが、主目的の dependency confusion 対策は上記の明示解決で達成できるため、全リポジトリの index 切替コストが見合わない と判断して採用していません。

Terraform で書くと、domain と repository はごくシンプルです。

resource "aws_codeartifact_domain" "this" {
  domain = "myorg"
  # encryption_key を指定しなければ AWS 管理キーが使われる(本用途では十分)
}

# upstream / external connection は持たない。
# public 依存はコンシューマ側から直接 PyPI 解決する構成。
resource "aws_codeartifact_repository" "internal" {
  domain      = aws_codeartifact_domain.this.domain
  repository  = "internal"
  description = "shared internal packages (Python). no external connections."
}

配置アカウントとクロスアカウント設計

なぜ本番(prd)アカウントに置くのか

レジストリは特定のデプロイ環境のものではなく、全環境のCI・全開発者が使う共有ビルドツール です。publish も pull も「ドメインを置いたアカウント」で行われるため、専用の共有アカウントを新設しないなら、既存アカウントのどれかに置く必要があります。

ここで採用したのは 本番(prd)アカウントに配置 です。一見「本番に開発ツールを置くの?」と思うかもしれませんが、決め手は 依存の向き です。

判断軸 内容
依存の向き(決め手) 全環境が「最も安定・最も統制されたアカウント」に依存する形になる。本番のデプロイ可能性を非本番アカウントに依存させない
dev を選ばない理由 本番が最も volatile な dev アカウントに依存する逆依存が生じてしまう
stg を選ばない理由 本番の再デプロイ / ホットフィックスが stg アカウントの健全性に依存してしまう

もし dev や stg にレジストリを置くと、本番をホットフィックスでデプロイし直したいときに、非本番アカウントが落ちているとデプロイできない、という逆依存が生まれます。最も安定したアカウントに全員が依存する のが健全な向きだと考えました。

read はアカウント単位、publish は OIDC で厳格に

配置アカウント以外の全消費アカウント(各サービスの dev / stg 環境など)は、CodeArtifact のリソースベースポリシーでクロスアカウント read を許可 します。ここで重要なのは、read は「アカウントの root 単位」で緩く許可し、書き込み(publish)は OIDC ロールで厳格に絞る という非対称な設計です。

read をアカウント root 単位にする理由は、開発者の SSO ロールでのローカル install が必然的に発生する ためです。CI ロールの ARN 単位で絞ると、開発者がローカルで poetry install するたびに権限エラーになり運用が破綻します。書き込みは後述の OIDC ロールで厳格に絞っているため、read の緩さは許容範囲です。

read を許可するリソースポリシーは次のようになります(消費アカウントの root ARN を principal にする)。

locals {
  # 消費アカウント ID のリストから root ARN を生成
  consumer_account_root_arns = [
    for id in values(var.consumer_account_ids) : "arn:aws:iam::${id}:root"
  ]
}

# repository policy: read 系 action を許可
data "aws_iam_policy_document" "repository" {
  statement {
    sid    = "AllowConsumerAccountsToReadInternal"
    effect = "Allow"
    actions = [
      "codeartifact:GetRepositoryEndpoint",
      "codeartifact:ReadFromRepository",
      "codeartifact:DescribePackage",
      "codeartifact:DescribePackageVersion",
      "codeartifact:GetPackageVersionAsset",
      "codeartifact:GetPackageVersionReadme",
      "codeartifact:ListPackages",
      "codeartifact:ListPackageVersions",
      "codeartifact:ListPackageVersionAssets",
      "codeartifact:ListPackageVersionDependencies",
    ]
    resources = [
      aws_codeartifact_repository.internal.arn,
      "${replace(aws_codeartifact_repository.internal.arn, ":repository/", ":package/")}/*",
    ]
    principals {
      type        = "AWS"
      identifiers = local.consumer_account_root_arns
    }
  }
}

# ポリシードキュメントは定義するだけでは効かない。repository へのアタッチが必要
resource "aws_codeartifact_repository_permissions_policy" "internal" {
  domain          = aws_codeartifact_domain.this.domain
  repository      = aws_codeartifact_repository.internal.repository
  policy_document = data.aws_iam_policy_document.repository.json
}

# クロスアカウントの認証トークン
data "aws_iam_policy_document" "domain" {
  statement {
    sid       = "AllowConsumerAccountsToGetAuthorizationToken"
    effect    = "Allow"
    actions   = ["codeartifact:GetAuthorizationToken"]
    resources = [aws_codeartifact_domain.this.arn]
    principals {
      type        = "AWS"
      identifiers = local.consumer_account_root_arns
    }
  }
}

resource "aws_codeartifact_domain_permissions_policy" "this" {
  domain          = aws_codeartifact_domain.this.domain
  policy_document = data.aws_iam_policy_document.domain.json
}

publish 経路のハードニング

書き込みは配置アカウント(本番)への CI 書き込みになるため、ここは厳格に絞ります。GitHub Actions の OIDC を使い、shared-packages リポジトリの特定ブランチ・タグからのみ assume できる publish 専用ロール を用意します。

  • OIDC trust の subshared-packages リポの develop ブランチ(プレリリース用)+ 全タグ(正式版用) に限定する
  • 権限は internal リポへの publish + token 取得だけ に限定し、本番アカウントの他リソースには一切アクセスできないようにする
# 既存の GitHub OIDC provider を参照(新規作成しない)
data "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"
}

locals {
  # リポジトリ識別子。
  publisher_repo = "myorg@1234567/shared-packages@98765432"

  # publish を許可する sub 条件(develop ブランチ + 全タグ)
  publisher_subs = [
    "repo:${local.publisher_repo}:ref:refs/heads/develop",
    "repo:${local.publisher_repo}:ref:refs/tags/*",
  ]
}

data "aws_iam_policy_document" "publish_assume" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]

    principals {
      type        = "Federated"
      identifiers = [data.aws_iam_openid_connect_provider.github.arn]
    }
    condition {
      test     = "StringEquals"
      variable = "token.actions.githubusercontent.com:aud"
      values   = ["sts.amazonaws.com"]
    }
    # develop ブランチ / タグの両方を許可(複数値の StringLike は OR)
    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = local.publisher_subs
    }
  }
}

resource "aws_iam_role" "publish" {
  name               = "shared-packages-publish"
  assume_role_policy = data.aws_iam_policy_document.publish_assume.json
}

publish ロールに与える権限も domain / repository にスコープを限定します。ここで一点ハマりどころがあります。PublishPackageVersion などの package 系アクションは repository/.../* のリソースにはマッチしませんarn:...:package/<domain>/<repo>/<format>/<namespace>/<package> 形式のリソースに対して評価されるため、package ARN を明示的に resources に含める必要があります。

data "aws_iam_policy_document" "publish" {
  # ドメイン単位の認証トークン取得。これが無いと publish 以前にトークンが取れず 403 になる
  statement {
    sid       = "GetAuthorizationTokenForDomain"
    effect    = "Allow"
    actions   = ["codeartifact:GetAuthorizationToken"]
    resources = [aws_codeartifact_domain.this.arn]
  }

  # CodeArtifact の認証は sts:GetServiceBearerToken も要求する
  statement {
    sid       = "GetServiceBearerTokenForCodeArtifact"
    effect    = "Allow"
    actions   = ["sts:GetServiceBearerToken"]
    resources = ["*"]
    condition {
      test     = "StringEquals"
      variable = "sts:AWSServiceName"
      values   = ["codeartifact.amazonaws.com"]
    }
  }

  statement {
    sid    = "PublishAndReadInternal"
    effect = "Allow"
    actions = [
      "codeartifact:GetRepositoryEndpoint",
      "codeartifact:ReadFromRepository",
      "codeartifact:PublishPackageVersion",
      "codeartifact:PutPackageMetadata",
      "codeartifact:DescribePackage",
      "codeartifact:DescribePackageVersion",
      "codeartifact:GetPackageVersionAsset",
      "codeartifact:ListPackages",
      "codeartifact:ListPackageVersions",
      "codeartifact:UpdatePackageVersionsStatus",
    ]
    resources = [
      aws_codeartifact_repository.internal.arn,
      "${replace(aws_codeartifact_repository.internal.arn, ":repository/", ":package/")}/*",
    ]
  }
}

# repository policy と同じく、ポリシードキュメントはロールにアタッチして初めて効く
resource "aws_iam_role_policy" "publish" {
  name   = "codeartifact-publish"
  role   = aws_iam_role.publish.id
  policy = data.aws_iam_policy_document.publish.json
}

共有リポ自身の CI 用に read 専用ロールも要る

権限設計は「read は消費アカウントに緩く、publish は OIDC で厳格に」の2本立てで語りましたが、実際にはもう1つ 共有リポ自身の CI 用 read 専用ロール が必要になりました。

内部パッケージが別の内部パッケージに依存していると、共有リポの PR CI で poetry install を走らせるだけでも CodeArtifact への read が発生します。ここで publish ロールを流用すると「PR ブランチから publish 権限を assume できる」ことになり本末転倒なので、全 ref から assume できるが read しか持たない 別ロールを分けます。

# trust の sub は全 ref 許可(read のみのため)。publish ロールとは完全に分離する。
condition {
  test     = "StringLike"
  variable = "token.actions.githubusercontent.com:sub"
  values   = ["repo:${local.publisher_repo}:*"]
}

ローカル開発体験を犠牲にしない3層モデル

レジストリ配布の唯一の弱点が「ローカル開発体験」です。共通パッケージを少し直して手元のサービスで動作確認したいだけなのに、毎回 publish して install し直すのでは開発が回りません。

そこで 環境ごとに依存解決の経路を変える3層モデル を採用します。

階層 環境 依存解決 反映タイミング
L1 ローカル path 依存(sibling 配置 + editable install) 編集→保存で即反映
L2 dev CodeArtifact の プレリリース版*.dev* 共有リポの push で自動 publish → 取得
L3 stg / prd CodeArtifact の 正式リリース版(lockfile 固定) タグ駆動 publish → 任意タイミングで取り込む

最重要なのは、pyproject.toml の宣言は全環境共通にしておき、ローカルだけ動的に path 依存へ書き換える という運用です。そして git にコミットされるのは常に CodeArtifact 依存版だけ にします。

pyproject.toml(全環境共通の宣言)

宣言は全環境共通で、CodeArtifact source を明示します。

[[tool.poetry.source]]
name = "codeartifact"
# <account-id> はレジストリを置いたアカウント(本記事では prd)。消費側のアカウント ID ではない
url = "https://myorg-<account-id>.d.codeartifact.ap-northeast-1.amazonaws.com/pypi/internal/simple/"
priority = "explicit"   # この source を明示指定した依存だけが CodeArtifact を見る

[tool.poetry.dependencies]
shared-models = { version = ">=0.1.0,<1", source = "codeartifact" }
shared-logger = { version = ">=0.1.0,<1", source = "codeartifact" }

各階層の操作

各階層の操作は次のようになります。

codeartifact-login は認証トークンを取得して export ... 文を標準出力に書くだけの Makefile ターゲットにしておき、呼び出し側で eval します。消費アカウントから叩くので --domain-owner にレジストリ配置アカウントの ID を渡す 必要があります(省略すると自分のアカウントのドメインを探しにいって失敗します)。

codeartifact-login:
	@TOKEN=$$(aws codeartifact get-authorization-token \
		--domain myorg --domain-owner <レジストリ配置アカウントID> \
		--region ap-northeast-1 --query authorizationToken --output text) && \
		printf 'export POETRY_HTTP_BASIC_CODEARTIFACT_USERNAME=aws\n' && \
		printf 'export POETRY_HTTP_BASIC_CODEARTIFACT_PASSWORD=%s\n' "$$TOKEN"

なお aws codeartifact login --tool が受け付けるのは npm / pip / twine / dotnet / nuget / swift の6つで、Poetry は対象外 です(指定すると Found invalid choice 'poetry' で弾かれます)。そのため Poetry では上記のように環境変数で渡しています。

# L1: ローカル(path 依存へ切替。editable install)
make link-shared                    # 共有パッケージを sibling への path 依存に置換

eval "$(make codeartifact-login)"   # ← unlink には CodeArtifact 認証が必要
make unlink-shared                  # CodeArtifact 依存に戻す

# L2: dev(プレリリース版を許可)
# ※ poetry update に --pre オプションは存在しない。プレリリース許可は
#    依存スペックの allow-prereleases でのみ表現できるため、CI のビルド内で
#    使い捨ての pyproject.toml に付与してから targeted update する
eval "$(make codeartifact-login)"   # CodeArtifact トークン取得(12時間有効)
# GNU sed 前提かつキーの並び順に依存する。恒久的に使うなら tomlkit 等で書き換える
sed -i 's/source = "codeartifact" }/source = "codeartifact", allow-prereleases = true }/' pyproject.toml
poetry update shared-models shared-logger --lock   # *.dev* を含む範囲内最新を lock
poetry install                      # --lock は lock を更新するだけなので install が要る

# L3: stg / prd(lockfile 固定の正式版)
eval "$(make codeartifact-login)"
poetry install                      # lockfile に固定された正式リリース版を取得

CI が Docker イメージのビルド内で install する場合は、取得したトークンを BuildKit の secret(--mount=type=secret)で渡し、イメージレイヤーに焼き込まない ようにします。ARGENV で渡すとイメージ履歴に残ります。

link-shared / unlink-shared の実体は、対象の pyproject.toml 群の依存行を差し替えて poetry lock し直す小さなスクリプトです。差し替える中身は次の2形態だけです。

# link 時(sibling への相対パス。develop = true が editable install の指定)
shared-logger = { path = "../../shared-packages/python/logger", develop = true }

# unlink 時(全環境共通の宣言に戻す)
shared-logger = { version = ">=0.1.0,<1", source = "codeartifact" }

poetry add --editable を並べる実装も考えられますが、行末コメント(# import 名は ... のまま など)が消える・複数の pyproject.toml を横断できないといった理由から、依存行だけを差し替えるスクリプトに落ち着きました。

注意点として、unlink-shared には CodeArtifact 認証が必要 です。CodeArtifact 依存に戻したうえで poetry lock を回すため、トークンが無いと解決に失敗します。逆に link-shared 側は、そのリポジトリが参照する内部パッケージをすべて path 依存へ切り替えられる場合に限り認証不要です(他リポジトリが publish している内部パッケージなど、手元に実体が無い依存が残るならトークンが要ります)。

L1 では path 依存なのでレジストリを見ず、CodeArtifact 認証すら不要です。共有パッケージを編集→保存すれば各サービスで即座に動作確認できます(editable install なので言語サーバの「Go to Definition」も共有パッケージのソースへジャンプできます)。共通化が「面倒さ」で阻害されない ことが、共通化を継続させるうえで一番効きます。

前提として、親リポと shared-packages を同一ディレクトリ階層に並べる sibling 配置 を規約とし、相対パス(../../shared-packages/<pkg>)が解決できる構造を保証します。

prj-root/                # 親ディレクトリ名は任意
├── shared-packages/
├── service-a/
└── service-b/

git にコミットされるのは常に CodeArtifact 依存

3層モデルで一番大事な不変条件がこれです。L1 のローカル動作のために make link-shared が path 依存へ書き換えますが、その書き換えは絶対に commit しません

これにより、CI/CD(dev/stg/prd ビルド)は git からチェックアウトしたコードを使うため、path 依存を見ることは構造上ありえません。環境ごとの挙動の違いは pyproject.toml ではなく、CI が呼ぶ install コマンドと lockfile の固定状態 だけで生まれます。

環境 依存解決の手順 取得する版
ローカル L1 make link-shared(editable) sibling 配置の共有パッケージを直接参照
CI L2(dev) allow-prereleases = true を sed 付与 → poetry update <pkg> --lock → install *.dev* プレリリース版
CI L3(stg / prd) poetry install(lockfile pin) 正式リリース版

バージョニング: タグを唯一の正とする

最後にバージョニングです。ここは地味ですが罠が多い領域です。

方針は 「タグが唯一の source of truth」 です。共有リポの各パッケージの pyproject.toml の version 欄は常に placeholder 0.0.0 にしておき、publish CI がビルド前に version を計算して上書き注入します。

  • 正式版: main 上でタグ(例 shared-models/v0.1.0)を push → タグ値そのものが version(0.1.0
  • プレリリース版: develop への push → 「直近タグの patch を +1 + .dev<コミット数>」を自動計算して publish

タグは <パッケージ名>/v<semver> で名前空間化し、バージョンはパッケージごとに独立して進めます。develop への push でも全パッケージを publish するのではなく、変更のあったパッケージだけ を対象にします(git diff --name-only <before>..HEAD の結果を各パッケージのパスと照合する)。初回 push や force push では github.event.before が全ゼロだったり到達不能だったりするので、その場合は全パッケージ対象へフォールバックさせておかないと publish が黙ってスキップされます。

プレリリース版の版番号は、素朴に「manifest version + .devN」とすると PEP 440 の順序の罠 にハマります。manifest が 0.1.0 のまま 0.1.0.dev5 を publish した後にタグ v0.1.0 を切ると、0.1.0.dev5 < 0.1.0 という順序関係により、dev 版が正式版より古い扱い になってしまいます。すると、プレリリースを許可した依存解決が新しい dev 版を拾わなくなります。

これを避けるため、「直近タグの patch+1 + .dev<N> で計算します。

# 直近タグ(パッケージ別の独立バージョニング)
LATEST=$(git describe --tags --match "shared-models/v*" --abbrev=0 2>/dev/null || true)
if [ -z "$LATEST" ]; then
  BASE="0.1.0"                       # タグが1つも無い間は patch+1 しない
else
  IFS=. read -r MAJ MIN PAT <<<"${LATEST#shared-models/v}"
  BASE="${MAJ}.${MIN}.$((PAT + 1))"
fi
# develop 上で単調増加するコミット数(run_number はリランで増えるため使わない)
N=$(git rev-list --count HEAD)
VERSION="${BASE}.dev${N}"
# 例: 直近タグが shared-models/v0.1.3 かつ N=482 なら → 0.1.4.dev482

こうすれば「dev 版 > 最新正式版」が成り立ち、プレリリース版が確実に拾われます。

lockfile については、コンシューマの lockfile は1つ(全ブランチで同じ内容)にし、stg/prd は lockfile pin の正式版を、dev は前述の allow-prereleases 方式で都度プレリリース版を取得します。正式版の更新 PR は Renovate がコンシューマの main ブランチに対して自動で作成 し、更新のやり忘れを防ぎます。プレリリース版は Renovate の追跡対象にせず(Renovate は既定でプレリリースを追わない)、dev デプロイ時に都度取得することで役割を分けます。

まとめ

マルチリポジトリ構成の共通 Python パッケージを、AWS CodeArtifact をプライベートレジストリとして「いい感じに」管理する設計を、実プロジェクトの意思決定を一般化する形でまとめました。
今回紹介した方法を採用することで「共通コードのコピーが乖離していく」という、マルチリポジトリでは避けがたい問題に対して、レジストリ配布 + 3層モデルは開発体験を犠牲にせず構造的に解決できる方式だと思います。同じ悩みを持つ方の参考になれば幸いです。

最後まで読んで頂いてありがとうございました。


そのマルチアカウント運用、気合いで支えていませんか

Organizations や Control Tower で土台は作れても、アカウントもポリシーも増えるほど、運用は「詳しい一人」に寄りかかっていく。属人化が限界を迎える前に、組織として回す仕組み=CCoEへ。5,600社の支援から得た立ち上げの型を、無料資料にまとめました。

CCoE総合支援

組織で回す仕組みの資料をもらう

この記事をシェアする

関連記事