S3にyumリポジトリを作成してプライベートサブネットから参照する

S3にyumリポジトリを作成してプライベートサブネットから参照する

プライベートサブネット内のAmazon Linux  2から、S3上の自作yumリポジトリにアクセスする

Amazon Linux  (2)の場合、プライベートサブネットからでも、S3バケット上に構築されているAmazon Linuxリポジトリを参照することで、yumを実行することができます。

Amazon Linux repositories are hosted in Amazon Simple Storage Service (Amazon S3) buckets. To update and install packages on your instance without an internet connection, create an S3 Amazon Virtual Private Cloud (Amazon VPC) gateway endpoint.

How can I update yum or install packages without internet access on my EC2 instances running Amazon Linux 1 or Amazon Linux 2?

ただしAmazon Linuxリポジトリから、全てのパッケージをインストールできるわけではありません。
例えばOracleやMicrosoft SQL ServerバージョンのRDSに接続するためには、専用のクライアントが必要になりますが、これらはNATゲートウェイ等を設置しなければ、EC2にインストールすることはできません。

そこで今回は、S3上に自作のyumリポジトリを構築します。
そのリポジトリに2種類のデータベースエンジン(Oracle、Microsoft SQL Server)のクライアントパッケージを格納し、プライベートサブネット内のインスタンスにインストールします。

構築する環境

Diagram of create yum repository in S3 and access from private subnet.

2つのVPCを作成します。
一方のVPCはyumリポジトリ作成用です。最新のAmazon Linux 2インスタンスを配置し、クライアント用リポジトリを作成し、S3バケットにアップロードします。
もう一方のVPCに、自作リポジトリの検証インスタンスを配置します。こちらのVPCにはインターネットゲートウェイやNATゲートウェイを配置せず、S3用VPCエンドポイントを経由して、S3バケットにアクセスします。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置してます。

https://github.com/awstut-an-r/awstut-fa/tree/main/031

テンプレートファイルのポイント解説

静的Webサイトホスティング機能を有効化して、S3バケットをyumリポジトリ化する

S3バケットを確認します。
ポイントは静的Webサイトホスティングに関する設定です。

Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref Prefix
      AccessControl: Private
      WebsiteConfiguration:
        IndexDocument: index.html
Code language: YAML (yaml)

WebsiteConfigurationプロパティで静的Webサイトホスティング機能を設定します。本機能を有効化することで、yumクライアントからのHTTP通信を受け付けることができます。
注意点はIndexDocumentプロパティです。本プロパティに「index.html」を設定します。これは本プロパティを設定しなければ、ホスティング機能が有効化できないためです。そのため実際にインデックスファイルを設置するわけではありませんが、形式的に設定します。

バケットポリシーでアクセス制限する

作成したバケットへのアクセスを、バケットポリシーを使って制限します。
ポイントはアクセスを許可する条件です。今回は以下の方針でアクセス制限します。

  1. 送信元のIPアドレスが、NATゲートウェイに付与したElastic IPアドレスの場合は、アクセスを許可する ※ VPC1内のインスタンス用
  2. 送信元のVPCがVPC2の場合は、アクセスを許可する ※ VPC2内のインスタンス用
Resources:
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - s3:*
            Effect: Allow
            Resource:
              - !Sub "arn:aws:s3:::${Bucket}/*"
            Condition:
              IpAddress:
                "aws:SourceIp":
                  - !Ref EIP
            Principal: "*"
          - Action:
              - s3:*
            Effect: Allow
            Resource:
              - !Sub "arn:aws:s3:::${Bucket}/*"
            Condition:
              StringEquals:
                "aws:SourceVpc":
                  - !Ref VPC
            Principal: "*"
Code language: YAML (yaml)

2つのポリシーを定義します。
1つ目のポリシーは、インスタンス1からのアクセスを許可するためのものです。Conditionプロパティがポイントです。IpAddressプロパティに「aws:SourceIp」およびNATゲートウェイに付与したElastic IPアドレスを設定することで、同アドレスからの通信を許可するポリシーとなります。インスタンス1がS3バケットにアクセスする際は、NATゲートウェイを経由し、送信元アドレスがElastic IPアドレスに付け替わるためです。
2つ目のポリシーは、インスタンス2からのアクセスを許可するためのものです。こちらもConditionプロパティで条件を設定します。StringEqualsプロパティに「aws:SourceVpc」およびVPC2のIDを設定することで、同VPC内からの通信を許可するポリシーとなります。

createrepoでリポジトリを作成して、S3バケットにアップロードする

yumリポジトリを作成するために、インスタンス1で実行する内容を確認します。

Resources:
  RunShellScriptAssociation1:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub "${Prefix}-runshellscript-association1"
      Name: AWS-RunShellScript
      Parameters:
        commands:
          - "sudo yum update -y"

          - !Sub "mkdir ${Repository}"

           # download oracle client
          - !Sub "curl  https://download.oracle.com/otn_software/linux/instantclient/1914000/{oracle-instantclient19.14-basic-19.14.0.0.0-1.x86_64.rpm} --output ./${Repository}/#1"
          - !Sub "curl  https://download.oracle.com/otn_software/linux/instantclient/1914000/{oracle-instantclient19.14-sqlplus-19.14.0.0.0-1.x86_64.rpm} --output ./${Repository}/#1"

          # download mssql-tools
          - "curl -OL https://packages.microsoft.com/config/rhel/7/prod.repo"
          - "sudo mv ./prod.repo /etc/yum.repos.d/msprod.repo"
          - !Sub "sudo yum install -y --downloadonly --downloaddir=./${Repository} mssql-tools"

          # create repository
          - "sudo yum -y install createrepo"
          - !Sub "createrepo ./${Repository}"

          - !Sub "aws s3 cp ./${Repository} s3://${Bucket}/ --recursive"
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance1
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

今回はインスタンス初期化処理の一環として、SSMドキュメントAWS-RunShellScriptを実行し、リポジトリ作成を行います。同ドキュメントを使用した初期化処理に関しては、以下のページをご確認ください。

あわせて読みたい
Linuxインスタンスの初期化方法4選 【Linuxインスタンスを初期化する4つの方法】 EC2インスタンスの起動時に初期化処理を実行する方法を考えます。 EC2インスタンスを構築時に初期化する以下の4つの手法を...

commandsプロパティで、実際に実行するコマンドを定義します。コマンドの内容は以下の通りです。

  • 事前準備(パッケージ更新、パッケージ格納用のディレクトリ作成)
  • Oracle用クライアント(sqlplus)パッケージのダウンロード
  • Microsoft SQL Server用クライアント(sqlcmd)パッケージのダウンロード
  • createrepoコマンドをインストールおよび実行して、上記ディレクトリをyumリポジトリ化する
  • AWS CLIを使用して、S3バケットにリポジトリデータをアップロードする。

なお各クライアントのインストール手順は、以下の公式サイトを参照しました。

https://docs.oracle.com/cd/F39414_01/lacli/install-instant-client-using-rpm.html

https://docs.microsoft.com/ja-jp/sql/linux/sql-server-linux-setup-tools?view=sql-server-ver15

S3用VPCエンドポイント

VPC2の方を確認します。
同VPCはインターネットとの接点を作成せず、VPCエンドポイントを通じて、S3バケットへアクセスします。

Resources:
  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref PrivateRouteTable
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
      VpcId: !Ref VPC
Code language: YAML (yaml)

特別な設定は不要です。
ServiceNameプロパティにS3を設定します。
S3用のVPCエンドポイントはゲートウェイタイプですから、VPC2のIDおよび同VPC内のサブネットに関連づいたルートテーブルを設定します。

yumに自作リポジトリを登録する

インスタンス2で実行する内容を確認します。
ポイントは自作したyumリポジトリを参照する方法です。

Resources:
  RunShellScriptAssociation2:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub "${Prefix}-runshellscript-association2"
      Name: AWS-RunShellScript
      Parameters:
        commands:
          - !Sub |
              sudo cat << EOF > /etc/yum.repos.d/${Repository}.repo
              [${Repository}]
              name=${Repository}
              baseurl=${BucketWebsiteURL}/
              gpgcheck=0
              enabled=1
              EOF
          - "sudo yum clean all"
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref Instance2
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

こちらもSSMドキュメントAWS-RunShellScriptを実行して、自作リポジトリ参照に必要な処理を行います。
一般に、yum実行時に参照されるリポジトリは、/etc/yum.repos.dディレクトリ配下の設定ファイルで定義します。同ディレクトリに、自作リポジトリ用の設定ファイルを作成・設置します。
今回は「myrepo」という名前でリポジトリを登録します。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • S3バケット:fa-031
  • インスタンス1:i-04533bae0ba1dd468
  • インスタンス2:i-054ec8995ebc83925

AWS Management Consoleからも、リソースの作成状況を確認します。
まずインスタンスの作成状況です。

Two instances are created.

確かに2つのインスタンスが作成されています。

次にインスタンス1におけるSSMドキュメントの実行結果を確認します。

SSM document successfully executed.

Outputから実行結果を確認することができます。

S3バケットを確認します。

The yum repository file is uploaded.

両クライアント用のパッケージ等が、バケットにアップロードされていることがわかります。

S3 static website hosting feature is enabled.

静的Webサイトホスティング機能が有効化され、HTTPリクエストを受け付ける準備が整っていることも確認できます。

自作リポジトリの登録状況を確認

準備が整いましたので、インスタンス2にアクセスします。
インスタンスへのアクセスは、SSM Session Managerを使用します。
詳細は以下のページをご確認ください。

あわせて読みたい
LinuxインスタンスにSSM Session Manager経由でアクセスする 【LinuxインスタンスにSSM Session Manager経由でアクセスする】 EC2インスタンスにSSM Session Manager経由でアクセスする構成を確認します。 Session Manager は完全...
% aws ssm start-session \
--target i-054ec8995ebc83925

Starting session with SessionId: root-0ec77415ecf2fb260

sh-4.2$Code language: JavaScript (javascript)

自作リポジトリの登録用ファイルを確認します。

sh-4.2$ ls -l /etc/yum.repos.d/
total 12
-rw-r--r-- 1 root root 1003 Oct 26 17:55 amzn2-core.repo
-rw-r--r-- 1 root root 1105 Mar 16 01:52 amzn2-extras.repo
-rw-r--r-- 1 root root  105 Mar 19 02:02 myrepo.repo
Code language: Bash (bash)

確かにファイル(myrepo.repo)が作成されています。
中身も確認します。

sh-4.2$ cat /etc/yum.repos.d/myrepo.repo
[myrepo]
name=myrepo
baseurl=http://fa-031.s3-website-ap-northeast-1.amazonaws.com/
gpgcheck=0
enabled=1
Code language: Bash (bash)

baseurlの値に注目です。S3のWebサイトエンドポイントのURLが指定されています。これによって、myrepoを参照する際は、S3バケットにアクセスすることになります。

yumが認識しているリポジトリ一覧を確認します。

sh-4.2$ yum repolist
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
2 packages excluded due to repository priority protections
repo id                                                                repo name                                                                  status
amzn2-core/2/x86_64                                                    Amazon Linux 2 core repository                                             27418
amzn2extra-docker/2/x86_64                                             Amazon Extras repo for docker                                                 56
myrepo                                                                 myrepo                                                                       4+2
repolist: 27478
Code language: Bash (bash)

デフォルトのAmazon Linuxリポジトリに加え、myrepoが認識されていることがわかります。

myrepoからインストールできるパッケージを確認します。

sh-4.2$ yum list all | grep myrepo
msodbcsql17.x86_64                     17.9.1.1-1                     myrepo
mssql-tools.x86_64                     17.9.1.1-1                     myrepo
oracle-instantclient19.14-basic.x86_64 19.14.0.0.0-1                  myrepo
                                       19.14.0.0.0-1                  myrepo
sh-4.2$
Code language: Bash (bash)

myrepoが正常に認識され、両クライアントがインストールできる状態であることがわかります。

Oracle用クライアントのインストール

まずOracle用クライアントをインストールします。

sh-4.2$ sudo yum install -y oracle-instantclient19.14-basic.x86_64
...
Installed:
  oracle-instantclient19.14-basic.x86_64 0:19.14.0.0.0-1

Complete!


sh-4.2$ sudo yum install -y oracle-instantclient19.14-sqlplus.x86_64
...
Installed:
  oracle-instantclient19.14-sqlplus.x86_64 0:19.14.0.0.0-1

Complete!
Code language: Bash (bash)

正常にインストールできました。

インストールされたパッケージを確認します。

sh-4.2$ yum list installed | grep oracle
oracle-instantclient19.14-basic.x86_64
oracle-instantclient19.14-sqlplus.x86_64
Code language: Bash (bash)

確かにmyrepoからOracleクライアントがインストールされました。

バージョンも確認します。

sh-4.2$ sqlplus -V

SQL*Plus: Release 19.0.0.0.0 - Production
Version 19.14.0.0.0
Code language: Bash (bash)

正常にバージョンが表示されました。

Microsoft SQL Server用クライアントのインストール

まずSQL Server用クライアントをインストールします。

sh-4.2$ sudo yum install -y mssql-tools
...
Installed:
  mssql-tools.x86_64 0:17.9.1.1-1

Dependency Installed:
  libtool-ltdl.x86_64 0:2.4.2-22.2.amzn2.0.2               msodbcsql17.x86_64 0:17.9.1.1-1               unixODBC.x86_64 0:2.3.1-14.amzn2

Complete!
Code language: Bash (bash)

正常にインストールできました。

インストールされたパッケージを確認します。

sh-4.2$ yum list installed | grep mssql-tools
mssql-tools.x86_64                    17.9.1.1-1                     @myrepoCode language: PHP (php)

確かにmyrepoからSQL Serverクライアントがインストールされました。

バージョンを確認します。

sh-4.2$ /opt/mssql-tools/bin/sqlcmd -?
Microsoft (R) SQL Server Command Line Tool
Version 17.9.0001.1 Linux
Copyright (C) 2017 Microsoft Corporation. All rights reserved.
...
Code language: Bash (bash)

正常にバージョンが表示されました。

まとめ

S3上に、自作のyumリポジトリを構築する方法を確認しました。
自作リポジトリを参照することで、Amazon Linuxリポジトリに存在しないパッケージについても、プライベートサブネット内のインスタンスにインストールすることができました。