[GCP] CloudSQL과 VPC 네트워크에 대한 이해
안녕하세요 김세호입니다.
Cloud SQL은 구글클라우드에서 제공하는 데이터베이스 서비스로 MySQL, PostgreSQL, SQL Server 엔진을 위한 완전 관리형 서비스로 제공하며 데이터베이스의 안정성, 보안성 확장성을 보장하며 백업, 복제, 패치, 용량확장을 자동화하면서 99.95%의 가용성을 보장합니다.
데이터베이스를 이용한 서비스를 구성시에는 중요한 데이터가 저장되는 데이터베이스를 독립된 네트워크 또는 서브넷에 생성하고 다양한 접근제어 방법을 이용하여 보안성이 높은 구성을 하게 됩니다. 또한, 완전 관리형 데이터베이스 서비스의 경우 클라우드 프로바이더가 관리하는 네트워크 환경에 데이터베이스 인스턴스를 생성하기 때문에 사용자의 서버 로그인 (SSH, RDP)은 원천적으로 불가능하며, 해당 데이터베이스 서비스로의 접근만 허용을 하고 있습니다.
사용자 네트워크 환경에서 관리형 데이터베이스 서비스에 접근을 하기 위한 구성은 다음 두가지 형태가 일반적인데요,
[구성1]
[구성1]의 경우는 관리형 데이터베이스는 클라우드 프로바이더가 관리하는 분리된 네트워크 환경에 데이터베이스 인스턴스를 생성하고, 해당 인스턴스의 네트워크 인터페이스만 사용자 네트워크 환경내 서브넷에 생성하는 방식으로, 사용자 네트워크 환경을 벗어나지 않고 데이터베이스에 접속을 할 수 있도록 하는 방식 입니다.
[구성2]
[구성2]의 경우도 마찬가지로 관리형 데이터베이스는 클라우드 프로바이더가 관리하는 분리된 네트워크 환경에 데이터베이스 인스턴스를 생성하지만, 네트워크 인터페이스를 사용자 네트워크내에 생성하는 대신 피어링이라는 기능을 이용하여 서로다른 네트워크 환경을 연결하고 비공개 서비스 액세스를 통하여 안전하게 프라이빗 통신을 할 수 있도록 제공하는 방식입니다.
각각의 구성은 특장점이 있겠지만 구글클라우드의 Cloud SQL의 경우는 [구성2]의 방식으로 사용자 네트워크와 데이터베이스 네트워크를 연결하도록 비공개 IP를 이용한 네트워크 피어링 방식을 이용하고 있습니다.
비공개 IP를 이용한 Cloud SQL 연결을 사용할 경우 “할당된 IP 주소 범위”를 정의하고 비공개 서비스 연결을 만들어야 하는데, 주소범위는 Cloud SQL 인스턴스가 사용할 IP주소를 포함하고 이는 VPC 네트워크와 겹칠 수 없습니다.
아래와 같은 dev-test-a라는 VPC 네트워크에 비공개 서비스 연결(Private Service Connection)을 생성하여 Cloud SQL과 프라이빗 통신을 하도록 구성을 해보겠습니다.
구글 클라우드 콘솔로 접속하여 “Menu” → “Networking” → “VPC Network”를 선택합니다. 테스트를 위한 기존 생성된 VPC를 선택하거나 위의 dev-test-a와 같은 커스텀 VPC를 생성하고 클릭합니다.
VPC 상세정보 화면에서 “Private service connection” 탭을 클릭합니다. 현재는 할당된 IP 주소 범위가 없음을 확인할 수 있습니다.
“Allocate IP Range” 버튼을 클릭하여 주소 범위를 할당합니다.
IP 주소 범위는 Custom, Automatic 2가지 옵션 중 선택을 할 수 있습니다. 주소 범위는 사용자 VPC에 할당된 IP 범위와 겹치지 않도록 Custom을 이용하여 입력합니다. Automatic은 구글 클라우드에서 자동으로 IP 범위를 선택하여 생성하도록 하는 옵션입니다.
IP 주소 범위를 입력후 “Allocate” 버튼을 클릭합니다.
비공개 서비스 연결 구성이 완료되었으면 Cloud SQL을 생성하기 위해 구글 클라우드 콘솔에서 “Menu” → “Storage” → “SQL” 메뉴로 이동을 합니다.
Cloud SQL 생성을 위해 상단의 “+CREATE INSTANCE” 를 클릭하고, 3가지 데이터베이스 엔진중 “MySQL” 을 선택합니다.
- Instance ID : 데이터베이스 인스턴스이름을 입력합니다.
- Root password : 데이터베이스 루트사용자 비밀번호를 입력합니다.
- Region : 사용자 VPC와 동일한 지역을 선택합니다.
- Configuration options의 1. Connectivity를 확장하여 아래와 같은 설정을 이용하여 비공개 서비스 연결을 이용한 프라이빗 통신을 하도록 구성합니다.
- Private IP를 선택합니다.
- Associated networking : 위에서 생성한 테스트할 사용자 VPC 네트워크를 선택합니다.
- Manged services network connection : 비공개 서비스 연결에서 생성한 IP 주소 범위를 지정합니다.
- Public IP는 선택하지 않습니다.
- “Connect” 버튼을 클릭합니다. (* 작업이 완료되기까지 7–10분의 시간이 소요될 수 있습니다)
- 추가 옵션 등을 설정합니다.
- Create 버튼을 클릭하여 데이터베이스를 생성합니다.
Cloud SQL 생성이 완료되면 아래와 같이 SQL 목록에서 확인이 가능하고, 데이터베이스 인스턴스의 IP 주소, 리젼정보 등을 확인할 수 있습니다.
사용자 VPC (dev-test-a) 에서 Cloud SQL로의 접속을 테스트하기 위하여 가상머신을 1대 생성하고 해당 인스턴스로 접속을 테스트 합니다.
# MySQL 클라이언트를 설치합니다.$ sudo apt-get update$ sudo apt-get install mysql-client# 생성한 CloudSQL에 접속 후, 쿼리를 실행합니다.$ mysql -h 10.10.0.3 -u root -pEnter password:Welcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 22Server version: 5.7.25-google-log (Google)Copyright © 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.MySQL [(none)]> show databases;+ — — — — — — — — — — +| Database |+ — — — — — — — — — — +| information_schema || mysql || performance_schema || sys |+ — — — — — — — — — — +4 rows in set (0.00 sec)MySQL [mysql]> select Host, User from mysql.user;+ — — — — — -+ — — — — — -+| Host | User |+ — — — — — -+ — — — — — -+| % | root || localhost | mysql.sys |+ — — — — — -+ — — — — — -+2 rows in set (0.00 sec)
구글 클라우드는 클라이언트가 Cloud SQL에 연결하는 다양한 방법을 제공하고 있습니다.
- SSL을 이용하는 IP 주소 연결
- SSL을 사용하지 않는 IP 주소 연결
- Cloud SQL 프록시
- Cloud SQL 프록시 Docker 이미지
- JDBC 소켓 라이브러리
- GO 프록시 라이브러리
- CloudShell
- Apps Script
위 테스트의 경우는 mysql 명령어를 이용한 연결을 이용하였는데요, 이는 암호화를 하지 않은 연결옵션을 이용한 경우 였습니다.
SSL 암호화를 적용하고자 할 경우에는
- 구글 클라우드 콘솔에 접속하여 “Menu” → “Storage” → “SQL” 에서 암호화 연결을 테스트 할 데이터베이스 인스턴스명을 클릭합니다.
- 좌측 메뉴에서 “Connections”를 클릭합니다.
- Connections 상세 페이지의 하단에 SSL 관련 섹션으로 이동합니다.
- SSL 접속만 허용을 하거나, 서버 Cert파일을 생성, 로테이트 하는 등의 옵션들을 볼 수 있습니다.
- “Create a client certificate” 버튼을 클릭합니다.
- 3개의 pem 파일을 다운로드 후, 이를 이용한 Cloud SQL 접속 명령을 이용하여 SSL 접근을 테스트 합니다.
사용자 VPC (dev-test-a) 에서 CloudSQL로의 접속을 테스트하기 위하여 생성했던 인스턴스로 접속하여 테스트를 진행합니다.
# 다운로드한 pem파일을 이용하여 CloudSQL에 SSL 접속 테스트를 합니다.$ mysql — ssl-ca=server-ca.pem — ssl-cert=client-cert.pem — ssl-key=client-key.pem — host=10.10.0.3 — user=root — passwordEnter password:Welcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 525Server version: 5.7.25-google-log (Google)Copyright © 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.# \s 를 입력하여 SSL 정보를 확인합니다.MySQL [(none)]> \s — — — — — — — mysql Ver 15.1 Distrib 10.1.44-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2Connection id: 525Current database:Current user: root@10.30.0.2SSL: Cipher in use is AES256-SHACurrent pager: stdoutㄷㅌUsing outfile: ‘’Using delimiter: ;Server: MySQLServer version: 5.7.25-google-log (Google)Protocol version: 10Connection: 10.10.0.3 via TCP/IPServer characterset: utf8Db characterset: utf8Client characterset: utf8mb4Conn. characterset: utf8mb4TCP port: 3306Uptime: 1 hour 37 min 8 secThreads: 5 Questions: 10301 Slow queries: 0 Opens: 173 Flush tables: 1 Open tables: 163 Queries per second avg: 1.767 — — — — — — — # pem 파일이 없는 기존 연결의 경우 “Not in use” 라고 표시됩니다.SSL: Not in use
SSL 인증서를 이용하는 방법외에 구글 클라우드에서 제공하는 Cloud SQL 프록시를 이용하는 방법에 대해서도 알아 보도록 하겠습니다.
CloudSQL 프록시는 승인된 네트워크 또는 SSL 구성을 추가할 필요 없이 보안 액세스를 제공하며, 다음과 같은 이점이 있습니다.
- 보안 연결: 프록시는 128비트 AES 암호화를 지원하는 TLS 1.2를 사용하여 데이터베이스와 주고받는 트래픽을 자동으로 암호화합니다. SSL 인증서는 클라이언트 및 서버 ID를 확인하는 데 사용됩니다.
- 연결 관리 간소화: 프록시가 Cloud SQL 인증을 처리하므로 고정 IP 주소를 제공할 필요가 없습니다.
Cloud SQL 프록시의 작동방식은 다음과 같습니다.
Cloud SQL 프록시는 로컬 환경에서 실행되는 프록시라고 하는 로컬 클라이언트를 사용하여 작동합니다. 애플리케이션은 데이터베이스에서 사용하는 표준 데이터베이스 프로토콜을 사용하여 프록시와 통신합니다. 프록시는 보안 터널을 사용하여 서버에서 실행 중인 컴패니언 프로세스와 통신합니다.
Cloud SQL 프록시는 Linux, Windows, macOS를 지원하고 있으며, 이번에는 Linux용 버전을 이용하여 설치 및 테스트를 해보도록 하겠습니다.
* 사용중인 운영체제가 포함되지 않으면 소스에서 프록시를 컴파일 하여 사용할 수 있습니다.
프록시를 사용하여 연결할 때는 프록시가 구글 클라우드 플랫폼으로 인증해야 합니다. Cloud SDK 사용자 인증 정보를 사용하거나, 생성한 서비스 계정의 로컬 키 파일 경로를 프록시에 제공할 수 있습니다.
서비스 계정을 사용하여 프록시 사용자 인증 정보를 제공하는 경우 충분한 권한을 부여해야 합니다. 세분화된 Identity Access and Management(IAM) 역할을 사용하여 CloudSQL 권한을 관리하는 경우 서비스 계정에 cloudsql.instances.connect 권한이 있는 역할을 부여해야 합니다.
구글 클라우드 콘솔에 접속하여 “Menu” → “Products” → “IAM & Admin” → “Service Accounts” 로 이동합니다.
- “+CREATE SERVICE ACCOUNT” 를 클릭하여 새로운 서비스 계정을 생성합니다.
- 서비스 계정 만들기 대화상자에 서비스 계정을 설명하는 이름을 입력하고, “Create” 버튼을 클릭합니다.
- 역할에서 다음 중 하나를 선택하고, “Continue” 버튼을 클릭합니다.
- Cloud SQL > Cloud SQL 클라이언트
- Cloud SQL > Cloud SQL 편집자
- Cloud SQL > Cloud SQL 관리자
- “Done”을 클릭하여 서비스 계정을 생성합니다.
서비스 계정 목록에서 Actions을 이용하여 “Create key”를 클릭하여 생성한 계정의 키를 생성, 다운로드 합니다.
다음으로 프록시가 데이터베이스에 연결할때는 IP 주소가 아닌 연결 이름을 이용하기 때문에 해당 이름을 다음과 같은 방법으로 확인해 둡니다.
구글 클라우드 콘솔에 접속하여 “Menu” → “Storage” → “SQL” 에서 연결이름을 확인 할 데이터베이스 인스턴스명을 클릭합니다.
데이터베이스 상세페이지에서 연결 이름을 확인하여 메모해 둡니다.
사용자 VPC (dev-test-a) 에서 Cloud SQL로의 접속을 테스트하기 위하여 생성했던 인스턴스로 접속하여 테스트를 진행합니다.
# Linux 버전 프록시를 다운로드 합니다.$ wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy$ chmod +x cloud_sql_proxy# 프록시를 실행합니다.$ ./cloud_sql_proxy -instances=popori-gcct-pj:asia-northeast1:dev-test-a-mysql=tcp:3306 -credential_file=popori-gcct-pj-9f4371555e6f.json2020/06/15 08:31:26 Rlimits for file descriptors set to {&{8500 1048576}}2020/06/15 08:31:26 using credential file for authentication; email=dev-test1-sql-sa@popori-gcct-pj.iam.gserviceaccount.com2020/06/15 08:31:27 Listening on 127.0.0.1:3306 for popori-gcct-pj:asia-northeast1:dev-test-a-mysql2020/06/15 08:31:27 Ready for new connections# CloudSQL로 프록시를 통하여 접속 후, 쿼리를 실행합니다.$ mysql — host 127.0.0.1 — port 3306 -u root -pEnter password:Welcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 1629Server version: 5.7.25-google-log (Google)Copyright © 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.MySQL [(none)]> select Host, User from mysql.user;+ — — — — — -+ — — — — — -+| Host | User |+ — — — — — -+ — — — — — -+| % | root || localhost | mysql.sys |+ — — — — — -+ — — — — — -+2 rows in set (0.00 sec)# 데이터베이스 연결시 프록시 로그에는 새로운 접속에 대한 로그가 출력됩니다.2020/06/15 08:34:00 New connection for “popori-gcct-pj:asia-northeast1:dev-test-a-mysql”
현재까지 테스트한 내용은 다음과 같은 구성으로 만들어져 있는것을 확인 할 수 있습니다.
이번에 확인해 볼 내용은 여러개의 VPC가 존재하는 상황에서 서로 다른 VPC에 위치한 Cloud SQL 데이터베이스에 접근을 하고자 할 경우 입니다.
여러개의 개발환경, 스테이지, QA 환경을 각 VPC로 구성하고 있는 상황이라면 다른 VPC에 존재하는 데이터베이스에 연결해야 하는 요구사항이 필요할 수 있습니다.
즉 아래와 같은 구성에서,
- dev-test-a에 있는 인스턴스 A에서 우측하단의 CloudSQL B로 접속이 필요한 경우 어떻게 해주어야 할까요?
- dev-test-a에 있는 인스턴스 A에서 프록시를 이용하여 좌측하단, 우측하단 두개의 CloudSQL A/B에 동시에 연결이 필요한 경우 어떤 설정이 필요하게 될까요?
- On-prem 데이터센터와 전용선 또는 VPN을 연동하고, 데이터센터에서 우측하단 CloudSQL B로 연결을 하려면 어떻게 해야할까요?
dev-test-a와 dev-test-b VPC를 피어링하고, dev-test-a의 인스턴스 A에서 dev-test-b의 데이터베이스 B로의 연결은 현재 구글 클라우드의 VPC에서 transit 기능을 지원하지 않기 때문에 접근이 불가능합니다.
먼저, 기존 dev-test-a에서 진행했던 설정을 dev-test-b도 동일하게 적용하여 아래와 같은 구성이 되도록 준비합니다. dev-test-b의 VPC는 10.40.0.0/16을 이용하고, Cloud SQL의 주소 범위는 10.20.0.0/24를 이용하도록 합니다.
구성이 완료되었다면 dev-test-a와 dev-test-b VPC간에 네트워크 피어링을 구성합니다.
구글 클라우드 콘솔에 접속하여 “Menu” → “VPC Network” → “VPC network peering” 을 클릭합니다.
- 상단의 “+CREATE PEERING CONNECTION”을 클릭합니다.
- dev-test-a → dev-test-b 로 피어링을 생성하기 위해 아래와 같이 정보를 입력합니다.
- “Create” 버튼을 클릭하여 피어링을 생성합니다.
- 상단의 “+CREATE PEERING CONNECTION”을 다시 클릭합니다.
- dev-test-b → dev-test-a 로 피어링을 생성하기 위해 아래와 같이 정보를 입력합니다.
- “Create” 버튼을 클릭하여 피어링을 생성합니다.
피어링의 구성은 연결하려는 2개의 VPC에서 모두 설정을 해야 하고, 설정이 정상적으로 완료되면 다음과 같이 상태가 Active로 표시되는것을 확인할 수 있습니다.
피어링이 정상적으로 작동하는지 확인하기 위하여 각 VPC에 생성해둔 인스턴스에 접속하여 연결테스트를 진행합니다.
dev-test-a-vm1 에 ssh 접속
$ hostname -I10.30.0.2$ ping -c 3 10.40.0.2PING 10.40.0.2 (10.40.0.2) 56(84) bytes of data.64 bytes from 10.40.0.2: icmp_seq=1 ttl=64 time=1.16 ms64 bytes from 10.40.0.2: icmp_seq=2 ttl=64 time=0.258 ms64 bytes from 10.40.0.2: icmp_seq=3 ttl=64 time=0.350 ms — — 10.40.0.2 ping statistics — -3 packets transmitted, 3 received, 0% packet loss, time 2014msrtt min/avg/max/mdev = 0.258/0.590/1.163/0.407 ms
dev-test-b-vm1 에 ssh 접속
$ hostname -I10.40.0.2$ ping -c 3 10.30.0.2PING 10.30.0.2 (10.30.0.2) 56(84) bytes of data.64 bytes from 10.30.0.2: icmp_seq=1 ttl=64 time=0.197 ms64 bytes from 10.30.0.2: icmp_seq=2 ttl=64 time=0.239 ms64 bytes from 10.30.0.2: icmp_seq=3 ttl=64 time=0.288 ms — — 10.30.0.2 ping statistics — -3 packets transmitted, 3 received, 0% packet loss, time 2027msrtt min/avg/max/mdev = 0.197/0.241/0.288/0.039 ms
질문으로 다시 돌아가서,
dev-test-a에 있는 인스턴스 A에서 dev-test-b에 있는 CloudSQL B로 접속이 필요한 경우 어떻게 해주어야 할까요?
dev-test-a와 dev-test-b는 피어링으로 연결이 되어있고, dev-test-b는 CloudSQL B와 피어링이 되어있는 상태지만, 앞서 언급한대로 A, B, C 3개의 VPC가 존재하고 A — B, B — C가 피어링이 되어있는 상태에서 A — C로의 연결은 불가능하다고 알고 있다.
실제로 dev-test-a의 인스턴스 A에서 dev-test-b와 피어링된 CloudSQL B로 연결을 테스트해 보면, 다음과 같이 데이터베이스로 연결이 되지 않는것을 알 수 있다.
$ hostname -I10.30.0.2$ mysql -h 10.20.0.3 -u root -pEnter password:$ telnet 10.20.0.3 3306Trying 10.20.0.3…^C
접속이 가능하게 하는 방법을 생각해보면, dev-test-a와 dev-test-b는 피어링으로 연결이 가능하고, dev-test-b는 피어링된 Cloud SQL B와 연결이 가능하기 때문에 dev-test-b의 인스턴스 B에 프록시를 설정하고 dev-test-a 인스턴스 A가 dev-test-b 프록시를 통하여 Cloud SQL B에 접속하도록 구성이 가능하다.
구성을 해보면 다음과 같고, 접속에 문제가 없음을 확인할 수 있다.
# dev-test-b 인스턴스 B에 프록시를 설정한다.$ hostname -I10.40.0.2# 외부 접속을 허용하기 위한 포트바인딩부분을 기존 tcp:3306 에서 tcp:10.40.0.2:3306으로 변경하였다.$ ./cloud_sql_proxy -instances=popori-gcct-pj:asia-northeast1:dev-test-b-mysql=tcp:10.40.0.2:3306 -credential_file=popori-gcct-pj-9f4371555e6f.json# dev-test-a 인스턴스 A에서 CloudSQL B로 접속한다.$ hostname -I10.30.0.2$ mysql -h 10.40.0.2 -u root -pEnter password:Welcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 226Server version: 5.7.25-google-log (Google)Copyright © 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.MySQL [(none)]> select Host, User from mysql.user;+ — — — — — -+ — — — — — -+| Host | User |+ — — — — — -+ — — — — — -+| % | root || localhost | mysql.sys |+ — — — — — -+ — — — — — -+2 rows in set (0.00 sec)
프록시를 이용하여 여러 데이터베이스 인스턴스에 연결을 하고자 하는 경우에는 -instances 매개 변수를 사용하여 연결이름을 쉼표(,)로 구분할 경우 프록시가 각 인스턴스로 연결을 제공합니다.
./cloud_sql_proxy -instances=myProject:us-central1:myInstance=tcp:3306,myProject:us-central1:myInstance2=tcp:3307
추가로, On-prem과 구글 클라우드가 전용선 또는 VPN을 이용하여 연결되어있고, On-prem 장비에서 클라우드의 데이터베이스로 연결을 할 경우는 다음과 같이 클라우드 라우터를 이용하여 직접 라우팅이 되거나, 프록시를 통하여 연결하는 구성 또한 가능합니다.
Disclaimer: 본 글의 작성자는 Google 직원이지만 Google Cloud 를 공부하는 한 개인으로서 작성된 글입니다. 본 글의 내용, 입장은 Google 을 대변하지 않으며 Google 이 해당 콘텐츠를 보장하지 않습니다.
참고 자료
Cloud SQL Private IP
https://cloud.google.com/sql/docs/mysql/private-ip
About the Cloud SQL Proxy
https://cloud.google.com/sql/docs/mysql/sql-proxy