Red Hat OpenShift Service on AWS w/STS のhands-on (2022年末版)

> 今朝はサッカー見てて、死ぬほど眠いけど、日付変わるまでに書くぞー！`rosa create cluster --sts`もするぞー！٩(ˊᗜˋ*)و 

## Red Hat OpenShift Service on AWS とは

通称、ROSA（ロサ）と呼ばれる本サービスは、Red Hat社とAWS社が共同でマネージドするOpenShiftのマネージドサービスになります。通常、OpenShiftのサブスクリプションは代理店などから購入するものですが、ROSAの場合はAWSから請求されるスキームとなっています。また、[on EC2やon VMwareでOpenShiftを稼働させるケースと比べて、OpenShiftのライセンスが非常に安い](https://aws.amazon.com/jp/rosa/pricing/)ことも特徴であると言えます。

> * ROSA service fees accrue on demand, at an hourly rate of $0.171 per 4 vCPU used by worker nodes, plus a $0.03 per hour cluster fee.
> * Service fees are not charged for the control plane or required infrastructure nodes.
> * 1-year and 3-year** ROSA service contracts offer savings between 33% and 55% off the on-demand service fees for worker nodes.
> * ROSA service fees are uniform across all supported AWS Regions. 

OpenShift4以降、（OpenShift3に比べて）インストールには大きなセットアップ作業を必要としなくなったものの、構築後のSelf-Managedの負荷は残ります。その点、本サービスはそういうものを減らすことができ、利用者のワークロードの開発により一層集中できるサービスと言えます。大まかな、Red Hat社との役割分担は[責任分担マトリクス](https://access.redhat.com/documentation/ja-jp/red_hat_openshift_service_on_aws/4/html/introduction_to_rosa/rosa-policy-responsibility-matrix)をご覧ください。
読みたくない人向けに、ざっくりまとめると以下の通りです。（**殆ど**や**多い**などの表現を使っています。ケースバイケースです）

* Master Nodeは殆ど面倒見なくていい
* Infra Node、Worker Node上で動いているワークロードは殆ど面倒を見ないといけないが、K8s的なクラスタとしての機能は殆ど面倒見なくていい
* アップデートのタイミングは利用者でコントロールができるし、バージョンも利用者で指定できる（＝能動的にバージョンアップ戦略を立てないといけない）
* `openshift-*`系のプロジェクトの多くはRed Hatが面倒を見てくれるが、利用者はそのリソースの変更ができないことが多い

## GAされてからもう直ぐ２年

2021年3月にGAとなった本サービスは、もう直ぐ２周年を迎えます。一見、本サービスはOpenShiftと同じ進化を辿っているように思われがちですが、この２年弱の間に以下のようなROSA固有のアップデートがありました。特にセキュリティ関連のアップデートが早々に行われたところは注目すべきポイントだと思います。

* STSモードでのインストールが可能になった（元々はOpenShift向けのIAM Userが必要だった）
* ROSAの運用を支援してくれるRed Hat SREチームがPrivate Link経由でアクセス可能になった（元々はSREチーム向けのInternetからのInboundアクセスが必要だった）
* cluster-wide proxyでのインストールが可能になった（元々はL3のルーティングでの外部アクセス経路が必要だった）
* 使えるリージョンが増えた（大阪でも使える）
* ライフサイクルが伸びた（マイナーバージョンが出てから14ヶ月間サポートされる。今のOpenShift 4.11は2023年10月10日まで）

他にも、細かいアップデートがあり、更新頻度も高いです。私はこれのウォッチは、[ROSA CLIのリポジトリ](https://github.com/openshift/rosa/releases)で行っています。

## Installing ROSA Cluster (w/STS + Private Link + Cluster-wide proxy on Your VPC)

ROSAは「ちょっと軽くお試しするか...」ぐらいのテンションで、**取り敢えず起動する**は結構簡単にできます。ただ、GAされてから機能もドキュメントも頻度高く更新されており、前述の追加機能を全て駆使したインストールの例が少ないので、2022年末時点のインストールメモを以下にダンプします。

### 前提条件

* 手元の端末にAWS CLIが導入されていて、`Administrator Access`の権限がセットされている
* `aws configure`で設定可能なデフォルトリージョンがROSAをインストールするリージョンにセットされている（今回は大阪リージョン、ap-northeast-3）
* [AWS Service Quota](https://docs.openshift.com/rosa/rosa_planning/rosa-sts-required-aws-service-quotas.html#rosa-sts-required-aws-service-quotas)の文書通り、必要に応じて上限緩和申請を行っている
* AWSのManagement Console経由で[Red Hat OpenShift Service on AWSのページ](https://console.aws.amazon.com/rosa/)にアクセスし、ROSAを有効化している
* [Red Hat Account](https://cloud.redhat.com/)が作成済みである

### ROSA CLI の導入

まず、手元の端末（MacBook）にCLIを導入します。

[Red Hat Hybrid Cloud Console](https://console.redhat.com/openshift/downloads)から`rosa cli`をダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/1a252ddc-0d10-42e9-de9f-5a25c1446bd9.png)

続いて、`rosa-macosx.tar.gz`を展開し、実行権限を付与します。

```zsh
$ tar zxvf rosa-macosx.tar.gz
$ chmod +x rosa
$ mv rosa /usr/local/bin/rosa
```

### ROSA用のVPCを作る

個人で試す上で、ROSAをMulti-AZ上に構築するのは、お財布に優しくないので、Single-AZのVPCをCloudFormationでサクッと作ります。

```yaml
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  RegionParameter:
    Type: String
    Default: ap-northeast-1
    AllowedValues:
      - ap-northeast-1
      - ap-northeast-2
      - ap-northeast-3

Resources:
  CfVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      Tags:
        -
          Key: Name
          Value: CfVPC

  CfPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      VpcId: !Ref CfVPC
      AvailabilityZone: !Join
      - ''
      - - !Ref RegionParameter
        - 'a'
      Tags:
        - Key: Name
          Value: CfPublicSubnet
  CfPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: 10.0.2.0/24
      MapPublicIpOnLaunch: false
      VpcId: !Ref CfVPC
      AvailabilityZone: !Join
      - ''
      - - !Ref RegionParameter
        - 'a'
      Tags:
        - Key: Name
          Value: CfPrivateSubnet

  CfInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: CfInternetGateway

  AttachCfInternetGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId : !Ref CfInternetGateway
      VpcId: !Ref CfVPC

  CfRouteTableForPublicSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: CfRouteTableForPublicSubnet

  CfRouteForPublicSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref CfRouteTableForPublicSubnet
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref CfInternetGateway

  CfAssocciateRouteTableForPublicSubnet:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableForPublicSubnet
      SubnetId: !Ref CfPublicSubnet

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  CfNatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
          - NatGatewayEIP
          - AllocationId
      SubnetId: !Ref CfPublicSubnet
      Tags:
        - Key: Name
          Value: CfNatGateway

  CfRouteTableForPrivateSubnet:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref CfVPC
      Tags:
        - Key: Name
          Value: CfRouteTableForPrivateSubnet

  CfRouteForPrivateSubnet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref CfRouteTableForPrivateSubnet
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref CfNatGateway

  CfAssocciateRouteTableForPrivateSubnet:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref CfRouteTableForPrivateSubnet
      SubnetId: !Ref CfPrivateSubnet
```

上述のCloudFormationのテンプレートには、`RegionParameter`を持たせています。今回は、**大阪リージョン**で作成します。

![スクリーンショット 2022-12-02 21.29.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/65318331-5d64-d845-94ef-caa10f0aa2d6.png)


スタックの作成が終わったら、**出力**タブに移動して、`CfPrivateSubnet`と`CfPublicSubnet`の値をメモしておきます。
* `CfPrivateSubnet`は、ROSAのクラスタが配置されるサブネットであり、インストールの時のパラメータで使用します。
* `CfPublicSubnet`は、この後作成するForward Proxyが配置されるサブネットであり、EC2を起動する時のパラメータで使用します。

![スクリーンショット 2022-12-02 21.33.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/32d657de-087a-bcfa-28e7-020aa2de13f8.png)

### Forward Proxyを作る

続いて、cluster-wide proxyでのインストール用に、Forward Proxyを構築します。
先ほどメモした`CfPublicSubnet`のパラメータも用いて、以下の構成で起動します。

* OS -> Amazon Linux
* Instance Type -> t2.micro
* Subnet ID -> 先ほどメモした`CfPublicSubnet`
* Public IP -> On
* Key Pair -> 任意のもの
* Security Group -> 自分のIPからのSSHと`10.0.0.0/16`からの全てのトラフィックを許可

EC2が起動したら、SSHでログインし、ApacheでForward Proxyを作っていきます。

```bash
# Apache等をインストール
$ sudo yum install httpd httpd-devel mod_ssl

# Forward Proxy用の設定ファイルを作成
$ sudo tee /etc/httpd/conf.d/proxy.conf << EOF > /dev/null
> Listen 3128
> <IfModule proxy_module>
>   ProxyRequests On
>   ProxyVia      On
>   ProxyTimeout  300
>   AllowCONNECT 443
>   CustomLog logs/proxy_log combined
> 
>   <Proxy *>
>     Order allow,deny
>     Allow from all
>   </Proxy>
> </IfModule>
> EOF

# Apacheを再起動して、自動起動の設定も入れる。
$ sudo systemctl start httpd.service
$ sudo systemctl enable httpd.service

# テストする
$ curl -LI https://example.com -x http://localhost:3128  -o /dev/null -w '%{http_code}\n' -s
200
$ sudo tail -n 10 /var/log/httpd/proxy_log
127.0.0.1 - - [02/Dec/2022:12:57:05 +0000] "CONNECT example.com:443 HTTP/1.1" 200 - "-" "curl/7.79.1"
```

### ROSAをインストールする

さて、ここからROSAのインストールです。ROSA CLIをインストールしている手元の端末から構築します。

```zsh
# ROSA CLIのバージョン確認
% rosa version
1.2.8

# rosa loginする（トークンは `https://console.redhat.com/openshift/token/rosa/show` から）

% rosa login --token="eyJ...snip...WN4"

# Install時に使うIAM Roleや各種Nodeで利用するEC2 Roleを作成する
# ここでインストールの前提条件の確認もやってくれる

% rosa create account-roles --prefix rosa2022 --mode auto -y
I: Logged in as '1ksen' on 'https://api.openshift.com'
I: Validating AWS credentials...
I: AWS credentials are valid!
I: Validating AWS quota...
I: AWS quota ok. If cluster installation fails, validate actual AWS resource usage against https://docs.openshift.com/rosa/rosa_getting_started/rosa-required-aws-service-quotas.html
I: Verifying whether OpenShift command-line tool is available...
I: Current OpenShift Client Version: 4.11.9
I: Creating account roles
I: Creating roles using 'arn:aws:iam::68xxxxxxxx92:user/1ksen-aws-iam'
I: Created role 'rosa2022-Installer-Role' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-Installer-Role'
I: Created role 'rosa2022-ControlPlane-Role' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-ControlPlane-Role'
I: Created role 'rosa2022-Worker-Role' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-Worker-Role'
I: Created role 'rosa2022-Support-Role' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-Support-Role'
I: To create a cluster with these roles, run the following command:
rosa create cluster --sts

# rosa create cluster --stsする
# インストールパラメータをインタラクティブに聞いてくれる。

% rosa create cluster --sts
I: Enabling interactive mode
? Cluster name: rosa2022
? OpenShift version: 4.11.16
W: More than one Installer role found
? Installer role ARN: arn:aws:iam::68xxxxxxxx92:role/rosa2022-Installer-Role
I: Using arn:aws:iam::68xxxxxxxx92:role/rosa2022-Worker-Role for the Worker role
I: Using arn:aws:iam::68xxxxxxxx92:role/rosa2022-Support-Role for the Support role
I: Using arn:aws:iam::68xxxxxxxx92:role/rosa2022-ControlPlane-Role for the ControlPlane role
? External ID (optional): 
? Operator roles prefix: rosa2022-q7f7
? Multiple availability zones (optional): No
? AWS region: ap-northeast-3
? PrivateLink cluster (optional): Yes
? Subnet IDs (optional): subnet-01c655bab4b8ebe2a (ap-northeast-3a)
? Enable Customer Managed key (optional): No
? Compute nodes instance type: m5.xlarge
? Enable autoscaling (optional): No
? Compute nodes: 2
? Machine CIDR: 10.0.0.0/16
? Service CIDR: 172.30.0.0/16
? Pod CIDR: 10.128.0.0/14
? Host prefix: 23
? Encrypt etcd data (optional): No
? Disable Workload monitoring (optional): No
? Use cluster-wide proxy (optional): Yes
? HTTP proxy (optional): http://10.0.1.17:3128/
? HTTPS proxy (optional): http://10.0.1.17:3128/
? No proxy (optional): 10.0.0.0/16
? Additional trust bundle file path (optional): 
I: Creating cluster 'rosa2022'

...snip...

# OpenShift内のOperatorが使うIAM Roleの作成をする

% rosa create operator-roles --cluster rosa2022 --mode auto -y
I: Creating roles using 'arn:aws:iam::68xxxxxxxx92:user/1ksen-aws-iam'
I: Created role 'rosa2022-q7f7-openshift-cloud-credential-operator-cloud-credenti' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-q7f7-openshift-cloud-credential-operator-cloud-credenti'
I: Created role 'rosa2022-q7f7-openshift-image-registry-installer-cloud-credentia' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-q7f7-openshift-image-registry-installer-cloud-credentia'
I: Created role 'rosa2022-q7f7-openshift-ingress-operator-cloud-credentials' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-q7f7-openshift-ingress-operator-cloud-credentials'
I: Created role 'rosa2022-q7f7-openshift-cluster-csi-drivers-ebs-cloud-credential' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-q7f7-openshift-cluster-csi-drivers-ebs-cloud-credential'
I: Created role 'rosa2022-q7f7-openshift-cloud-network-config-controller-cloud-cr' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-q7f7-openshift-cloud-network-config-controller-cloud-cr'
I: Created role 'rosa2022-q7f7-openshift-machine-api-aws-cloud-credentials' with ARN 'arn:aws:iam::68xxxxxxxx92:role/rosa2022-q7f7-openshift-machine-api-aws-cloud-credentials'

# 続いてManaged Serviceの中の人たちにAssume RoleするためのOIDC Providerの設定を入れる

% rosa create oidc-provider --cluster rosa2022 --mode auto -y
I: Creating OIDC provider using 'arn:aws:iam::68xxxxxxxx92:user/1ksen-aws-iam'
I: Created OIDC provider with ARN 'arn:aws:iam::68xxxxxxxx92:oidc-provider/rh-oidc.s3.us-east-1.amazonaws.com/20xxxxxxxxxxxxxxxxxxxxik'

# インストールの進捗を以下のコマンドで確認する

% rosa logs install -c rosa2022 --watch

# 最後に以下のテキストが出力されていたら、インストールが成功

...snip...

I: Cluster 'rosa2022' is now ready

```

### ROSAにアクセスする

まず、手元の端末の方で、`cluster-admin`を作成します。

```zsh
% rosa create admin --cluster=rosa2022
I: Admin account has been added to cluster 'rosa2022'.
I: Please securely store this generated password. If you lose this password you can delete and recreate the cluster admin user.
I: To login, run the following command:

   oc login https://api.rosa2022.xcfa.p1.openshiftapps.com:6443 --username cluster-admin --password xxxxx-xxxxx-xxxxx-xxxxx

I: It may take several minutes for this access to become active.
```

ここで得た、`oc login`のコマンドを、この環境であればForward Proxyなり、あなたの環境であれば個別に立てた踏み台サーバなり、VPNやDirect Connect経由でなりから実行すれば、アクセスすることができます。これは環境によって異なると思いますので、[ドキュメント](https://docs.openshift.com/rosa/rosa_install_access_delete_clusters/rosa-sts-accessing-cluster.html)を参考に、クラスタへのアクセスを検討してください。

### Productionに向けては

この記事のインストールでは、STSモードなどを使ってはいますが、本番で稼働させるにあたっては、他にもさまざまな考慮が必要です。

* `rosa create cluster --sts`の時のパラメータは、
    - Multi-AZ にして、
    - EBS暗号化などに使うキーはCMKを使って、
    - Worker Nodesのインスタンスタイプは、稼働させるワークロードに合わせて設定して、
    - Auto Scalingを有効にして、
    - etcdも暗号化する
* また、cluster-wide proxyはガバガバにしてると良くないので、Whitelist型のProxyに設定したほうがいい
    - 開けないといけないFQDNのリストは[こちら](https://docs.openshift.com/rosa/rosa_install_access_delete_clusters/rosa_getting_started_iam/rosa-aws-prereqs.html#osd-aws-privatelink-firewall-prerequisites_prerequisites)に記載あり
* などなど...

## お片付け

OpenShiftの費用は従量課金とはいえ、Nodeがいっぱい立ち上がっているので、お試し終わったら消しましょう。

```zsh
# 手元の端末からROSAクラスタの削除

% rosa delete cluster --cluster=rosa2022 -y 

# Operatorが使用していたIAM Roleを削除する
# マスクしているパラメータは、前述の`rosa delete cluster`を打った時の標準出力に出る

% rosa delete operator-roles -c 20xxxxxxxxxxxxxxxxxxxxik --mode auto -y
I: Fetching operator roles for the cluster: 20xxxxxxxxxxxxxxxxxxxxik
I: Successfully deleted the operator roles

# OIDC Providerの設定も吹っ飛ばす

% rosa delete oidc-provider -c 20xxxxxxxxxxxxxxxxxxxxik --mode auto -y
I: Successfully deleted the OIDC provider arn:aws:iam::68xxxxxxxx92:oidc-provider/rh-oidc.s3.us-east-1.amazonaws.com/20xxxxxxxxxxxxxxxxxxxxik

# EC2 Roleなども削除する

% rosa delete account-roles --prefix rosa2022 --mode auto -y
I: Successfully deleted the account roles

# CloudFormationのスタックを消す（Management Consoleからでも可）

% aws cloudformation delete-stack --stack-name rosa2022
```

## 〆

無事に大阪リージョンにROSAをSTSモードでcluster-wide proxyインストールすることができました。昔に比べると随分と簡単に自分のAWS環境へインストールできるようになったと思います。また、AWSの機能性とインテグレーションも進んだ結果、ローンチ時より遥かにセキュリティコントロールができるようになったとも思います。
ROSAの大きな特徴の１つである、従量課金を理解し、上手に活用することで、Productionはもちろんのこと、日々の開発環境としての用途で使うことも、クラスタ丸ごとDR環境で復元とかもやろうと思えばlightweightに出来ます。一方、手軽さと安さの特徴の裏では、BYOSのOpenShiftでできることがROSAでは制限がある（できない）ケースがあるので、ノーマリーな用途での利用が安全とも言えます。

最後に、日本でROSAのユーザがもっと増えたらいいなぁと思います。（間に合ったー！寝るぞー！）