5
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

GitHub ActionsでSrc IP制限のかかったサービス(AWS RDS)につなぐ

はじめに

GitHub Actionsは、GitHub上のコードに対して、PushやPullRequestをフックして、処理を実行できる処理基盤です。

このGitHub Actionsを使って自動テストや自動デプロイをするのですが、GitHub ActionsのワーカーのグローバルIPアドレスは毎回変わるため、Src IP制限のかかったサービスを使おうとするとうまくいきません。

そこで、この記事では、GitHub ActionsからSrc IP制限のかかったサービスを使う方法を、AWSのRDSを例に上げて説明します。

概要

処理の概要は以下のとおりです

  1. GitHub ActionsのワーカーのグローバルIPを、haythem/public-ip@v1.2 を使って取得する
  2. RDSのSecurity Groupに対して、取得したグローバルIPからの通信を一時的に許可する
  3. サービスにつないでやりたいことをやる
  4. 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_IDAWS_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 }}


Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
5
Help us understand the problem. What are the problem?