📘

閉域環境でのPythonパッケージ管理:インターネット接続なしのVPCでCodeArtifactを利用する

2024/12/10に公開

はじめに

阿河です。

閉域環境ではインターネットに直接アクセスできないため、Pythonパッケージの管理には特別な工夫が求められます。本記事では、AWS CodeArtifactを活用し、閉域環境でも安全かつ効率的にPythonパッケージを利用する方法をご紹介します。

特に、怪しいファイルや意図しないパッケージが閉域環境に持ち込まれるリスクを最小限にするため、安全なリポジトリ(以下では「Safeリポジトリ」と呼びます)を活用し、信頼されたパッケージのみを利用する運用フローの構築を目指します。

このアプローチにより、CodeArtifactの柔軟性を最大限に活用しながら、安全性と運用効率を両立する方法を提案します。

目次

  1. CodeArtifactリポジトリのセットアップ
  2. ネットワーク環境構築
  3. テスト用にSageMakerノートブックインスタンスの作成
  4. パッケージのインストール

1. CodeArtifactリポジトリのセットアップ

ドメインの作成


https://docs.aws.amazon.com/ja_jp/codeartifact/latest/ug/codeartifact-concepts.html

  • AWSマネジメントコンソールで、ドメインを作成。
  • リポジトリは、ドメインと呼ばれる上位レベルのエンティティに集約されます。すべてのパッケージ アセットとメタデータはドメインに保存されますが、リポジトリを通じて使用されます。
  • CodeArtifactのConceptはリンク先を御確認ください。

リポジトリの作成

  • リポジトリ名を指定。
  • リポジトリには、一連のパッケージ バージョンが含まれており、各バージョンは一連のアセットまたはファイルにマップされます。
  • パブリックアップストリームリポジトリとして、pypi-storeを指定しています。
  • CodeArtifactパブリックアップストリームリポジトリは、NPMなどの公式パッケージオーソリティにリポジトリを接続する中間リポジトリです。


https://docs.aws.amazon.com/ja_jp/codeartifact/latest/ug/repo-upstream-behavior.html

  • 外部接続からtest-artifact-domainを経由して、test-artifact-repositoryにパッケージがどのように流れるかを確認できます。
  • アップストリームリポジトリを持つ場合の挙動は上記リンクを参照ください。

  • 結果として2つのリポジトリが作成されます。

リポジトリエンドポイントの確認

aws codeartifact get-repository-endpoint \
    --domain test-artifact-domain \
    --repository test-artifact-repository \
    --format pypi \
    --region ap-northeast-1

https://docs.aws.amazon.com/cli/latest/reference/codeartifact/get-repository-endpoint.html

  • 特定のパッケージ形式のリポジトリのエンドポイントを返します。
  • 閉域環境で利用するためのリポジトリエンドポイントを確認します。

2. ネットワーク環境構築

テスト環境をCloudFormationで構築します。

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true

  Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: false

  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow access to VPC Endpoints
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0

  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Subnet
      RouteTableId: !Ref RouteTable

  S3GatewayEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref RouteTable

  CodeArtifactAPIVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.codeartifact.api"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      PrivateDnsEnabled: true

  CodeArtifactRepoVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.codeartifact.repositories"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      PrivateDnsEnabled: true

  SageMakerNotebookVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "aws.sagemaker.ap-northeast-1.notebook"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      PrivateDnsEnabled: true

  SageMakerAPIVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.sagemaker.api"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      PrivateDnsEnabled: true

  STSVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.sts"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      PrivateDnsEnabled: true

  LogsVPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub "com.amazonaws.ap-northeast-1.logs"
      VpcEndpointType: Interface
      SubnetIds:
        - !Ref Subnet
      SecurityGroupIds:
        - !Ref SecurityGroup
      PrivateDnsEnabled: true

Outputs:
  VPCId:
    Description: "VPC ID"
    Value: !Ref VPC
    Export:
      Name: App-VPC

  SubnetId:
    Description: "Subnet ID"
    Value: !Ref Subnet
    Export:
      Name: App-Subnet

  SecurityGroupId:
    Description: "Security Group ID"
    Value: !Ref SecurityGroup
    Export:
      Name: App-SecurityGroup
  • 設定は環境に合わせて変更してください。

3. テスト用にSageMakerノートブックインスタンスの作成

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  SageMakerNotebookRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: "sagemaker.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: SageMakerAccessPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "codeartifact:GetRepositoryEndpoint"
                  - "codeartifact:ReadFromRepository"
                  - "codeartifact:GetAuthorizationToken"
                  - "codeartifact:ListPackages"
                  - "codeartifact:ListDomains"
                Resource: "*"
              - Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:PutObject"
                Resource: "arn:aws:s3:::xxxxxx/*"
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: "arn:aws:logs:*:*:*"
              - Effect: Allow
                Action:
                  - "sts:AssumeRole"
                  - "sts:GetCallerIdentity"
                  - "sts:GetServiceBearerToken"
                Resource: "*"

  SageMakerNotebookInstance:
    Type: AWS::SageMaker::NotebookInstance
    Properties:
      InstanceType: ml.t3.medium
      RoleArn: !GetAtt SageMakerNotebookRole.Arn
      SubnetId: !ImportValue App-Subnet
      SecurityGroupIds:
        - !ImportValue App-SecurityGroup
      NotebookInstanceName: Test-Notebook-Instance
      DirectInternetAccess: "Disabled"   
  • SageMakerノートブックインスタンスは、インターネットアクセスをOFFにしています。
  • 「xxxxxx」は環境に合わせてS3バケットを指定してください。

4. パッケージのインストール

デフォルトでインストールされているパッケージの確認

import pkg_resources

installed_packages = sorted([(d.project_name, d.version) for d in pkg_resources.working_set])
for package in installed_packages:
    print(f"{package[0]}=={package[1]}")
  • SageMakerノートブックインスタンスにログインし、上記コードを実行します。
  • SageMaker ノートブックインスタンスにデフォルトでインストールされている Pythonパッケージを確認します。
  • 私の環境ではstreamlitが入っていないようなので、次の検証でインストールしてみます。

CodeArtifactからいくつかパッケージをインストール

!aws codeartifact login --tool pip \
    --domain test-artifact-domain \
    --domain-owner xxxxxxxxx \
    --repository test-artifact-repository \
    --region ap-northeast-1
  • domain-ownerにはAWSアカウント番号を入力
!pip install streamlit
  • Streamlitをインストール
  • 少し時間はかかるが、インストール成功。
streamlit                          1.40.2
  • インストールされたことが確認できます。
!pip install pandas --upgrade --force-reinstall
  • 既にノートブックにインストールされていたPandasは再インストールを行っても、パッケージを取りに行く挙動を行いませんでした。

https://pip.pypa.io/en/stable/ux-research-design/research-results/pip-force-reinstall/

  • こちらでPandsの再インストールおよびリポジトリへのパッケージ反映がされました。

おわりに

今回の解説を通じて、AWS CodeArtifactを活用した閉域環境でのPythonパッケージ管理の基盤が構築できました。現時点ではPyPIのコピーリポジトリを用いていますが、追加でSafeリポジトリを用意することで、信頼されたパッケージのみを利用できる仕組みを導入し、怪しいファイルや意図しないパッケージが閉域環境に持ち込まれるリスクをさらに低減する運用フローに繋げることができます。

完全にリスクを排除するには、CodeArtifactのリポジトリポリシーやIAMポリシーを適切に設定し、さらに運用面での管理を強化する必要があります。これらを補完するための「Safeリポジトリ」の活用が、安全な運用を支える重要な鍵と考えます。

閉域環境でのパッケージ管理には特有の課題がありますが、AWSのサービスを組み合わせることで、安全性と効率性を両立した運用を実現できる可能性があります。今後も最新のAWSサービスやセキュリティに関する情報を活用し、より堅牢な運用方法を模索していきたいと考えています。

MEGAZONE株式会社 Tech Blog

Discussion