Egress Networkingを考えてから、ROSA（STS+Private Link）をつくる（Squid透過プロキシ版）

## 前回は（AWS Network Firewall版）だった。

* 前回は[こちら](https://qiita.com/1ksen/items/d3b99e490eb375c68636)
* Network Firewallだと、高可用でマネージドサービスだからHappyなことも多い。
* だけど、ROSAでお腹いっぱいなので、ベーシックな技術でアウトバウンドアクセスの経路を作りたくもある。（コンチと言う名の逃避）

## URL Filtering可能な透過プロキシ

* 透過プロキシは、いわゆるNAT InstanceやNAT Gatewayの実装と同じと思っている。
* Linux上で実装する場合、iptablesを使うことで、同じようなことができる。
* ただ、iptablesだとip filteringはできても、url filteringはできない。
* けど、前回のNAT Gateway + Network Firewallでは、url filteringはできた。
* 多分、TLS SessionからSNIを読み取って、フィルタリングするような実装なんだと思う（適当）

## on-EC2でURL FilteringできるNAT Instanceを作りたい ＞＜

* 仲間を探していたら、[神がいた](https://aws.amazon.com/jp/blogs/security/how-to-add-dns-filtering-to-your-nat-instance-with-squid/)。squidで実装できるって、、まじか。

> For HTTPS requests, the HTTP traffic is encapsulated in a TLS connection between the instance in the private subnet and the remote host. Squid cannot retrieve the host header field because the header is encrypted. A feature called SslBump would allow Squid to decrypt the traffic, but this would not be transparent for the client because the certificate would be considered invalid in most cases. The feature I use instead, called SslPeekAndSplice, retrieves the Server Name Indication (SNI) from the TLS initiation. The SNI contains the requested Internet host. As a result, Squid can make filtering decisions without decrypting the HTTPS traffic.

## 今日の構成図


* URL Filteringかけないと怒られるので、squidでwhitelistを持ちたい
* だから、squidのEC2にルーティングされるアクセスは全てSquidにForwardさせる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/1609ad57-f598-867c-37b2-0d1b234b5d33.png)

## 環境変数の設定

クラスターのセットアップに使う情報を環境変数に埋める。

```bash
$ export VERSION=4.8.5 \
>         ROSA_CLUSTER_NAME=rosacluster \
>         AWS_ACCOUNT_ID=`aws sts get-caller-identity --query Account --output text` \
>         REGION=ap-northeast-1 \
>         AWS_PAGER="" \
>         VPC_CIDER=10.0.0.0/16
>         PRIVATE_SUBNET=10.0.0.0/17 \
>         PUBLIC_SUBNET=10.0.128.0/17
```

## 自前のVPCを準備する

### VPCの作成

VPCを作って、

```bash
$ VPC_ID=`aws ec2 create-vpc --cidr-block $VPC_CIDER | jq -r .Vpc.VpcId`
$ aws ec2 create-tags --resources $VPC_ID --tags Key=Name,Value=$ROSA_CLUSTER_NAME
$ aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames
```

### Subnetの作成

Public Subnetを作って、

```bash
$ PUBLIC_SUBNET=`aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.128.0/17 | jq -r .Subnet.SubnetId`
$ aws ec2 create-tags --resources $PUBLIC_SUBNET --tags Key=Name,Value=$ROSA_CLUSTER_NAME-public
```

Private Subnetを作って、

```bash
$ PRIVATE_SUBNET=`aws ec2 create-subnet --vpc-id $VPC_ID  --cidr-block 10.0.0.0/17 | jq -r .Subnet.SubnetId`
$ aws ec2 create-tags --resources $PRIVATE_SUBNET --tags Key=Name,Value=$ROSA_CLUSTER_NAME-private
```

### Internet Gatewayの作成

IGWつくって、VPCにアタッチする。

```bash
$ I_GW=`aws ec2 create-internet-gateway | jq -r .InternetGateway.InternetGatewayId`
$ aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $I_GW
$ aws ec2 create-tags --resources $I_GW --tags Key=Name,Value=$ROSA_CLUSTER_NAME
```

### Route Tableの作成（Public Subnet用）

Route Tableを作って、IGWへのルーティングを追加して、Public SubnetにAssociateする。

```bash
$ R_TABLE=`aws ec2 create-route-table --vpc-id $VPC_ID | jq -r .RouteTable.RouteTableId`
$ aws ec2 create-route --route-table-id $R_TABLE --destination-cidr-block 0.0.0.0/0 --gateway-id $I_GW
{
    "Return": true
}
$ aws ec2 associate-route-table --subnet-id $PUBLIC_SUBNET --route-table-id $R_TABLE
{
    "AssociationId": "rtbassoc-0eXXXXXXXXXXXX1e",
    "AssociationState": {
        "State": "associated"
    }
}
$ aws ec2 create-tags --resources $R_TABLE --tags Key=Name,Value=$ROSA_CLUSTER_NAME
```

### squid instanceの作成

Public SubnetにAmazon Linux 2でEC2立ててから、以下のコマンドを実行する。（user-dataに放り込むようにしたい）
ここで、EC2の送信元・送信先チェックを無効化している。

```bash
#!/bin/bash -xe
# Apply the latest security patches
yum update -y --security

# Disable source / destination check. It cannot be disabled from the launch configuration
region=ap-northeast-1
instanceid=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
aws ec2 modify-instance-attribute --no-source-dest-check --instance-id $instanceid --region $region

# Install and start Squid
yum install -y squid
systemctl start squid || service squid start
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3129
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 3130
iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-port 3130

# Create a SSL certificate for the SslBump Squid module
mkdir /etc/squid/ssl
cd /etc/squid/ssl
openssl genrsa -out squid.key 4096
openssl req -new -key squid.key -out squid.csr -subj "/C=XX/ST=XX/L=squid/O=squid/CN=squid"
openssl x509 -req -days 3650 -in squid.csr -signkey squid.key -out squid.crt
cat squid.key squid.crt >> squid.pem

# Create Squid Confuguration
cat <<EOF > /etc/squid/squid.conf
visible_hostname squid
cache deny all

# Log format and rotation
logformat squid %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %ssl::>sni %Sh/%<a %mt
logfile_rotate 10
debug_options rotate=10

# Handle HTTP requests
http_port 3128
http_port 3129 intercept

# Handle HTTPS requests
https_port 3130 cert=/etc/squid/ssl/squid.pem ssl-bump intercept
acl SSL_port port 443
http_access allow SSL_port
acl step1 at_step SslBump1
acl step2 at_step SslBump2
acl step3 at_step SslBump3
ssl_bump peek step1 all

# Filter HTTPS requests based on the whitelist
ssl_bump peek all
ssl_bump splice all

http_access allow all
EOF

# Restart Squid Daemon
systemctl restart squid
```

### Route Tableの作成（Private Subnet用）

Route Tableを作って、

```bash
$ R_TABLE_NAT=`aws ec2 create-route-table --vpc-id $VPC_ID | jq -r .RouteTable.RouteTableId`
```

SquidのEC2にアタッチされているENIのIDをコピペしてきて...（ToDo：CLI化する）、ルーティングを追加する。

```bash
$ ENI=eni-xxxxxxxxxx
$ aws ec2 create-route --route-table-id $R_TABLE_NAT --destination-cidr-block 0.0.0.0/0 --network-interface-id $ENI
{
    "Return": true
}
$ aws ec2 associate-route-table --subnet-id $PRIVATE_SUBNET --route-table-id $R_TABLE_NAT
{
    "AssociationId": "rtbassoc-07XXXXXXXXXXXX45",
    "AssociationState": {
        "State": "associated"
    }
}
```

諸々、タグ付けする。

```bash
$ aws ec2 create-tags --resources $R_TABLE_NAT --tags Key=Name,Value=$ROSA_CLUSTER_NAME-private
```

### Disable source/destination checks

```
$ INSTANCE_ID=i-xxxxxxxxxxxx
$ aws ec2 modify-instance-attribute --no-source-dest-check --instance-id $INSTANCE_ID --region $REGION
```


## ROSAのインストール

```bash
# AWSの権限が十分かを確認する
rosa verify permissions

# ROSAに必要な各種RoleやPolicyをつくる
rosa create account-roles --mode auto --version "${VERSION%.*}" -y

# ROSAクラスタのインストールを開始する
rosa create cluster -y --sts --cluster-name ${ROSA_CLUSTER_NAME} \
    --region ${REGION} --version ${VERSION} \
    --subnet-ids=$PRIVATE_SUBNET \
    --private-link --machine-cidr=$VPC_CIDR \
    --support-role-arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/ManagedOpenShift-Support-Role \
    --role-arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/ManagedOpenShift-Installer-Role \
    --master-iam-role arn:aws:iam::${AWS_ACCOUNT_ID}:role/ManagedOpenShift-ControlPlane-Role \
    --worker-iam-role arn:aws:iam::${AWS_ACCOUNT_ID}:role/ManagedOpenShift-Worker-Role

# OIDCの設定をする
rosa create operator-roles -c $ROSA_CLUSTER_NAME --mode auto --yes
rosa create oidc-provider -c $ROSA_CLUSTER_NAME --mode auto --yes

# インストール状況のWatch
watch "rosa describe cluster -c $ROSA_CLUSTER_NAME"
```

## 結果発表～

### インストールの結果

できた。

```bash
$ rosa logs install -c $ROSA_CLUSTER_NAME 
I: Cluster 'rosa' has been successfully installed
```

### アクセス先ドメインとポートの一覧

AWSとOpenShiftとquayドメインをWhitelist化すればいけそう。
ちょっとわからんのも入ってる、、後で調べよう。（nosnch.in？？？）
Whitelistのもたせ方はsquidのwikiとかに載ってるはず。
ん～、nginxやapacheで同じことできないんかなぁ。squidの設定よくわからん。

```bash
$ sudo awk '{print $8}' access.log | sort -u
- 
api.openshift.com
cdn02.quay.io
cloud.redhat.com
ec2.ap-northeast-1.amazonaws.com
elasticloadbalancing.ap-northeast-1.amazonaws.com
infogw.api.openshift.com
nosnch.in
observatorium-mst.api.openshift.com
quay.io
quayio-production-s3.s3.amazonaws.com
registry.access.redhat.com
registry.redhat.io
rosacluster-88ndp-bootstrap.s3.ap-northeast-1.amazonaws.com
rosacluster-88ndp-image-registry-ap-northeast-1-mcleraufawrcfv.s3.dualstack.ap-northeast-1.amazonaws.com
route53.amazonaws.com
sso.redhat.com
sts.amazonaws.com
tagging.us-east-1.amazonaws.com

$ sudo awk '{print $7}' access.log | sed 's/^.*://g' | sort -u
443
```

おしまい。