はじめに
GitHub Actionsは、GitHub上のコードに対して、PushやPullRequestをフックして、処理を実行できる処理基盤です。
このGitHub Actionsを使って自動テストや自動デプロイをするのですが、GitHub ActionsのワーカーのグローバルIPアドレスは毎回変わるため、Src IP制限のかかったサービスを使おうとするとうまくいきません。
そこで、この記事では、GitHub ActionsからSrc IP制限のかかったサービスを使う方法を、AWSのRDSを例に上げて説明します。
概要
処理の概要は以下のとおりです
- GitHub ActionsのワーカーのグローバルIPを、
haythem/public-ip@v1.2
を使って取得する - RDSのSecurity Groupに対して、取得したグローバルIPからの通信を一時的に許可する
- サービスにつないでやりたいことをやる
- RDSのSecurity Groupに対して、取得したグローバルIPからの通信を一時的に遮断する
作り方
1. RDSのセキュリティグループを開け締めするプログラムを作る
まず、Security Groupを操作するためのプログラムをGo言語で作ります。
sgutil.go
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/rds"
"os"
"syscall"
)
const RDS_ID = "myrds" // RDSのID
const RDS_PORT = 5432 // RDSのポート
// cidrからの通信を許可するようにRDSのセキュリティグループを変更する。
// @param : ipAddr :通信を許可したいIPアドレス。
// @param : op : 操作。op=openで開ける。 op=closeで閉じる。
func securityGroupIngressControl(ipAddr string, op string) {
sess, err := session.NewSession(&aws.Config{Region: aws.String("ap-northeast-1")})
if err != nil {panic(err)}
rdsService := rds.New(sess)
// RDSのセキュリティグループの取得
input := &rds.DescribeDBClustersInput{DBClusterIdentifier: aws.String(RDS_ID)}
result, err := rdsService.DescribeDBClusters(input)
if err != nil {panic(err)}
securityGroupId := *(result.DBClusters[0].VpcSecurityGroups[0].VpcSecurityGroupId)
// security groupの操作
ec2Service := ec2.New(sess)
ipPermissions := []*ec2.IpPermission{
{
FromPort: aws.Int64(int64(RDS_PORT)),
ToPort: aws.Int64(int64(RDS_PORT)),
IpProtocol: aws.String("tcp"),
IpRanges: []*ec2.IpRange{{CidrIp: aws.String(ipAddr + "/32")}},
},
}
if op == "open" {
// security groupを開ける
input := &ec2.AuthorizeSecurityGroupIngressInput{
GroupId: aws.String(securityGroupId),
IpPermissions: ipPermissions,
}
_, err := ec2Service.AuthorizeSecurityGroupIngress(input)
if err != nil {panic(err)}
} else if op == "close" {
// security groupを閉じる
input := &ec2.RevokeSecurityGroupIngressInput{
GroupId: aws.String(securityGroupId),
IpPermissions: ipPermissions,
}
_, err := ec2Service.RevokeSecurityGroupIngress(input)
if err != nil {panic(err)}
} else {
panic("invalid op")
}
}
func printUsage() {
fmt.Printf("Argument ERROR. \n\nUsage: go run %s [open|close] IpAddress \n", os.Args[0])
}
func main() {
if len(os.Args) != 3 {
printUsage()
syscall.Exit(1)
}
op := os.Args[1] // 操作 [open|close]
ipAddr := os.Args[2]
securityGroupIngressControl(ipAddr, op)
}
※Go言語を用いなくても、bashとaws cliを駆使して実現することも可能ですが、少し複雑なプログラムのため、プログラミング言語で作りました。
2. GitHubのsecretsにAWSのクレデンシャル情報を追加する
今回は、AWS_ACCESS_KEY_ID
と AWS_SECRET_ACCESS_KEY
という名前に、それぞれAWSのシークレットを登録します。
3. Github Actionsのワークフローを作る
./github/workflows/my_action.yml
name: MyAction
on:
push:
# developブランチにpushされたら動き出す。
branches: [ develop ]
jobs:
my_action:
name: MyJob
runs-on: ubuntu-latest
steps:
# AWSのクレデンシャルをセット
- name: Create AWS credential Environment Variables
uses: aws-actions/configure-aws-credentials@v1
with:
# GitHubのSecretsに登録しておくと、secrets.XXXXで参照できる
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
# GitHub ActionsのワーカーのGlobalIPアドレスを取得するためのステップ
- name: Install Public IP Lib
id: ip
uses: haythem/public-ip@v1.2
# Go言語のセットアップ
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.15
# コードのチェックアウト
- name: checkout
uses: actions/checkout@v2
# RDSのセキュリティグループに対して、GitHub Actionsのワーカーからの通信を許可する
- name: Open RDS security group ingress from this IP
run: go run sgctl.go open ${{ steps.ip.outputs.ipv4 }} # steps.ip.outputs.ipv4でIPを参照できる
# DBに接続していろいろする
- name: Run DB Ops
run: xxxxxxxxx
# RDSのセキュリティグループに対して、GitHub Actionsのワーカーからの通信を閉じる
- name: Close RDS security group ingress from this IP
if: always() # alwaysをつけることにより、アクションが失敗しても必ず実行されるようにする
run: go run sgctl.go close ${{ steps.ip.outputs.ipv4 }}