데이터베이스 접근을 애플리케이션으로 제한

PostgreSQLBeginner
지금 연습하기

소개

현재 주문 데이터베이스는 애플리케이션 VPC 전체의 연결을 허용하며 애플리케이션은 데이터베이스 관리자 계정을 사용합니다. 네트워크 접근을 줄이고 주문을 읽고 추가할 수 있지만 삭제할 수 없는 전용 사용자를 만듭니다.

먼저 데이터베이스 연결 및 SQL 실습을 완료하세요. 이 독립 환경은 PostgreSQL 기본 데이터베이스, 예제 주문 세 건 및 애플리케이션을 제공합니다. 두 접근 경계를 테스트하고 마지막에 연습용 데이터베이스를 삭제합니다.

자격증 시험과의 연관성

이 실습은 다음 시험 주제를 위한 기초 실습을 제공합니다.

PostgreSQL 네트워크 소스 제한

이 단계에서는 넓은 VPC 인바운드 접근을 준비된 애플리케이션 보안 그룹에서의 접근으로 바꿉니다.

보안 그룹은 데이터베이스에 도달할 수 있는 네트워크 연결을 제어합니다. 인증된 데이터베이스 사용자가 수행할 SQL 작업은 결정하지 않습니다. 다음 단계에서 이 별도의 경계를 다룹니다.

준비된 설정을 불러옵니다.

cd /home/labex/project
source database.env

데이터베이스 그룹과 제공된 두 규칙 문서를 확인합니다.

aws ec2 \
  describe-security-groups \
  --group-ids "$DB_SECURITY_GROUP_ID" \
  --query 'SecurityGroups[].{Group:GroupName,Ingress:IpPermissions}'
cat broad-rule.json
cat application-rule.json

기존 규칙은 10.70.0.0/16에서 TCP 포트 5432로 접근을 허용하므로 VPC의 다른 클라이언트도 데이터베이스 연결을 시도할 수 있습니다. 새 규칙은 UserIdGroupPairs로 애플리케이션 그룹을 참조합니다. 보안 그룹 참조는 해당 소스 그룹에 연결된 리소스의 트래픽을 허용하며 소스 그룹 규칙을 복사하지 않습니다.

넓은 규칙을 제거하고 애플리케이션 규칙을 추가합니다.

aws ec2 \
  revoke-security-group-ingress \
  --group-id "$DB_SECURITY_GROUP_ID" \
  --ip-permissions file://broad-rule.json
aws ec2 \
  authorize-security-group-ingress \
  --group-id "$DB_SECURITY_GROUP_ID" \
  --ip-permissions file://application-rule.json

애플리케이션 소스에서 새 연결을 테스트합니다.

psql \
  "service=orders-db" \
  --command 'SELECT count(*) FROM orders;'

3이 표시되어야 합니다. 이어서 애플리케이션 그룹 밖에 있는 제공된 클라이언트를 테스트합니다.

psql \
  "service=orders-db-external" \
  --command 'SELECT count(*) FROM orders;'

외부 클라이언트 연결은 실패해야 합니다. 데이터베이스 비밀번호는 유효하지만 네트워크 소스가 허용되지 않습니다. 준비된 연결 이름은 이 두 소스를 선택합니다. 실습 접근 규칙은 Terminal이나 AWS View 관리 연결을 변경하지 않습니다.

AWS View에는 넓은 VPC CIDR 대신 애플리케이션 그룹이 데이터베이스의 PostgreSQL 소스로 표시되어야 합니다.

애플리케이션용 데이터베이스 사용자 생성

이 단계에서는 관리 권한이나 삭제 권한 없이 주문 읽기와 삽입을 허용합니다.

PostgreSQL 역할은 권한을 가질 수 있습니다. LOGIN 역할은 데이터베이스 사용자로 인증할 수 있습니다. 데이터베이스 역할은 AWS IAM 계정과 별개입니다. IAM은 RDS 리소스 관리를 승인하고 SQL 권한은 PostgreSQL 내부 작업을 제어합니다.

제공된 비공개 애플리케이션 비밀번호 파일로 orders_app을 만듭니다. --set은 psql 변수를 정의하고 :'app_password'는 해당 값을 SQL 문자열로 안전하게 인용합니다.

네트워크 접근, 로그인, SQL 권한은 별개의 경계임

개념도: 네트워크 접근, 로그인, SQL 권한은 별개의 경계임.

psql \
  "service=orders-db" \
  --set=ON_ERROR_STOP=1 \
  --set=app_password="$(cat app-password.txt)" <<'SQL'
CREATE ROLE orders_app LOGIN PASSWORD :'app_password';
GRANT CONNECT ON DATABASE orders TO orders_app;
GRANT USAGE ON SCHEMA public TO orders_app;
GRANT SELECT, INSERT ON orders TO orders_app;
SQL

CONNECT는 데이터베이스 연결을 허용합니다. USAGE는 테이블을 포함하는 이름 공간인 스키마를 통한 접근을 허용합니다. SELECT와 INSERT는 필요한 주문 작업만 허용합니다. DELETE, UPDATE, CREATEDB, CREATEROLE 또는 슈퍼유저 권한은 부여하지 않았습니다.

비공개 비밀번호 값을 psql에 전달하여 애플리케이션 역할을 테스트합니다.

PGPASSWORD="$(cat app-password.txt)" psql \
  "service=orders-db-app" \
  --command 'SELECT current_user, count(*) FROM orders;'

사용자 orders_app과 주문 수 3이 표시되어야 합니다.

존재하지 않는 주문 ID를 삭제해 봅니다. 실수로 권한을 너무 넓게 주었더라도 이 문장은 실제 주문을 삭제할 수 없습니다.

PGPASSWORD="$(cat app-password.txt)" psql \
  "service=orders-db-app" \
  --command 'DELETE FROM orders WHERE order_id = -1;'

permission denied for table orders가 표시되어야 합니다. 네트워크 연결과 데이터베이스 로그인이 성공한 뒤 발생한 실패이므로 앞선 외부 클라이언트의 연결 실패와 다른 경계를 증명합니다.

애플리케이션에서 제한된 계정 사용

이 단계에서는 애플리케이션에 역할을 설정하고 정상 주문 작업이 계속 작동함을 확인합니다.

두 엔드포인트 필드를 유지하면서 데이터베이스 사용자와 비밀번호 파일 참조를 변경합니다.

jq \
  '.user = "orders_app" | .password_file = "app-password.txt"' \
  app-config.json > app-config.new
mv app-config.new app-config.json

현재 주문 목록을 읽습니다.

curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

원래 주문 세 건과 user: orders_app이 표시되어야 합니다.

애플리케이션 HTTP 엔드포인트로 주문 하나를 추가합니다. Content-Type은 요청 본문이 JSON임을 알립니다.

curl \
  --silent \
  --show-error \
  --fail \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{"order_id":104,"customer":"Kai","total":"5.00"}' \
  http://127.0.0.1:8080/application/orders

saved: true와 주문 ID 104가 표시되어야 합니다. 목록을 다시 읽습니다.

curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

Kai의 5.00 주문을 포함한 네 건이 표시되어야 합니다. AWS View에도 동일한 저장 데이터와 제한된 애플리케이션 계정이 표시되어야 합니다. 권한을 줄여도 필요한 동작은 유지됩니다. 애플리케이션이 제한된 orders_app 데이터베이스 사용자로 기존 주문과 새 주문을 읽습니다.

연습용 데이터베이스 삭제

이 단계에서는 예제 주문과 SQL 사용자를 포함하여 실습 데이터베이스를 삭제합니다.

aws rds \
  delete-db-instance \
  --db-instance-identifier orders-db \
  --skip-final-snapshot \
  --query 'DBInstance.DBInstanceIdentifier'
aws rds \
  wait db-instance-deleted \
  --db-instance-identifier orders-db
aws rds \
  describe-db-instances \
  --query 'DBInstances[].DBInstanceIdentifier'

[]가 표시되어야 합니다. 데이터베이스 엔진과 역할이 삭제되어 애플리케이션의 이전 엔드포인트는 연결되지 않습니다. 제공된 네트워크와 접근을 제한한 데이터베이스 그룹은 유지하세요. 정리를 위해 데이터베이스 접근을 다시 열 필요는 없습니다.

요약

PostgreSQL 연결을 애플리케이션 소스로 제한하고 애플리케이션에 자체 제한 역할을 부여했습니다. 외부 클라이언트는 연결할 수 없고 애플리케이션 역할은 주문을 삭제할 수 없었지만 정상 읽기와 삽입은 계속 작동했습니다. 이어서 제한된 네트워크 규칙을 유지하면서 연습용 데이터베이스를 삭제했습니다.

다음 실습에서는 수동 RDS 스냅샷을 새 데이터베이스로 복원하여 잃어버린 주문을 되찾습니다.