반응형

개요

  • 내가 이걸 다하나?
  • 손이 너무 많이 간다... (고도화 전략 - %로 주기)
  • MYSQL Version Upgrade (5.7 -> 8.0)
  • 역시 손이 너무 많이간다 ... (고도화 전략 - Terraform 활용하기)

내가 이걸 다하나?


현재 회사에서 근무한지는 어언 11개월이 넘어가고

Devops 파트에서 팀리드가 된지는 6개월이 넘어가는 시점

나는, 우리는 DB를 어떻게 관리했고 앞으로는 어떻게 관리할건지 얘기해보겠다.

 

사실 DB는 각 회사에 DBA분이 다 하시는건지 알았다. (예전회사는 그랬으니... <- 바보같은 생각)

History가 굉장히 많지만, Database 에 대한 권한제어는 DevOps 파트에서 관리한다.

 

초반에는 아래와 같은 이유로 굉장히 손이 많이 갔었다.

  • 신규입사자 및 퇴사자 계정 추가 및 제거
  • 유저별 권한 추가 및 제어
  • 인덱스 별 쿼리 제어 및 DML 쿼리의 대한 검증

 

신규입사자 및 퇴사자 계정 추가 및 제거

## 유저생성
create user <username>@'%' identified by '<password>';


## 유저삭제
DROP user '<username>'@'%';

 

뭐 어떻게 보면 별거는 아니다.

신규입사자가 오면 유저를 생성하고, 퇴사자는 유저를 Drop 하면 된다.

 

뭐 금방금방 처리할수는 있지만, 갑자기 바쁠때 처리할라고하면 굉장히 은근 귀찮다.

해당 관련해서 다른 팀원들이 유저를 제거하기 위해 아래와같은 쿼리를 사용했다.

## mysql.user 에서 유저삭제?
DELETE FROM mysql.user WHERE user = <username>;

 

근데, 이렇게 하면 유저는 삭제되지만 부여된 권한이 삭제가 되지 않는다.

즉... 제대로 삭제가 안된다

 

유저별 권한 추가 및 제어

## 권한 추가
GRANT SELECT ON `prd_database`.table TO '<username>'@'%';

## 이거 꼭 해줘야 함
flush privileges; 

## 해당 유저에 권한 보기
SHOW GRANTS FOR <username>;

유저별 권한은 팀마다 챕터마다 사용하는 DB.Table 추가해주면 된다.

사실 이것도 크게 어렵진 않다. 하지만 물론 이것도 하다보면 손이 꽤 많이간다.

 

테이블이 없어지거나, 관리가 안된다면... 은근 빡세다

인덱스 별 쿼리 제어 및 DML 쿼리의 대한 검증

이건 크게 관리포인트라기 보다는...

우리회사 특이점 인지는 몰라도, 인덱스 및 쿼리검증은 Devops가 한다 (이게맞나? 싶지만 그것에 대한 의문은 하지않는다 -> 그게프로니까)

 

보통 인덱스 같은 경우, 아래와 같은 프로세스를 사용해서 진행한다

  1. RDS에 스냅샷 생성 (index-test)
  2. 생성된 스냅샷 DB에 인덱스 진행
  3. 인덱스 시간 및 process 점유 파악
  4. 금방끝나거나 가벼운작업이라면 진행하지만, 시간이 꽤 걸리는 작업이라면 공지하고 18시~19시 이후에 진행

쿼리에 대한검증도 보통... 위와같이 진행할 수 있다.

가끔 한방쿼리를 사용하는 사람도 있어서...


 

손이 너무 많이 간다 (고도화전략 - % 로 주기)

회사마다 다르겠지만 현재 우리회사의 DB.Table 숫자는 아래와 같았다.

  • Database : 40 + a
  • Table : 100 + a

이렇다보니.. 각 유저별 DB.Table 권한을 세세하게 주기가 너무어려웠다.

어떻게 하면 편하게 줄 수 있을까 해서... 편법이 떠올랐다.

## prd_database 구성된 테이블에 SELECT 권한 전체주기
GRANT SELECT ON `prd_database`.* TO '<username>'@'%';
flush privileges;

## prd로 시작하는 전테 데이터베이스.Table에 SELECT 권한 전체주기
GRANT SELECT ON `prd%`.* TO '<username>'@'%';
flush privileges;

 

이야... 이렇게 하니까 편하긴한데 문제는 여러가지가 발생하였다.

 

DB가 안돼요

가끔 Data Engineer 분이 본인 쿼리가 안된다고 한다.

근데 또 DB IDE를 껐다 키면 또 됐다가 안됐다가 오락가락 한다.

 

그 이유를 보니 권한 구성을 살펴보니 아래와 같았다.

개판...

그냥 내가 봤을때는 개판이었다.

빨간줄로 슥슥 그었지만, %와 raw 하게 권한을 준것이 짬뽕이되어, 뭔가 꼬이는게 아닐까 하는생각이 들었고,

%로 구성된 권한을 제외하니까 다시는 해당 이슈가 발생하지 않았다....

 

보안상 이슈

일단 결론적으로 말하면 % 형태로 권한을 부여하는것은 솔직히 좋지 않다.

특히 보안상... 왜냐하면 {prefix}% 시작하는 모든 DB.Table에 대해서는 부여된 권한을 사용할 수 있기 때문이다.

그럼 어떻게 해야할까...

어떻게 하면 보안상으로 훌륭하고, 우리팀의 손을 덜수 있을까? 


 

MYSQL Version Upgrade (5.7 -> 8.0) 

업무를 하다보니... 올때가 왔다.

대충 요약하면 MYSQL 5.7 버전이 이제 지원을 종료 하니 8.0 으로 버전을 올려라 이런 얘기다 

( 종료는 아니고 표준지원이 종료되니 -> 5.7을 사용할거면 돈을 더 내라... )

 

별다른 대책이 없다.

그래서 공지하고 기존 5.7 -> 8.0 으로 DB를 업그레이드 했다 (Blue/Green 방법 활용)

관련해서는 추후에 글을 한번 써볼예정임 -> 다사다난했음


역시 손이 너무 많이 간다 ( 고도화전략 - Terraform 활용하기 )

8.0 으로 버전을 올리면서 MYSQL에 내가 몰랐던 기능이 하나 추가되었다.

Role 추가

이 전까진 유저에 대해서 권한을 주고 뺐다 보니까, 굉장히 불편했다.

그런데 Role이 추가된다니... 나름 신세계 

AWS 를 주로사용하는 나로서는 RBAC 같은 기능을 나름 잘 사용했기 때문에 회사에 한번 적용해보기로 하였다.

Role 관련 쿼리

## Role 생성
CREATE ROLE 'role_name';

## Role 권한 부여
GRANT SELECT, INSERT, UPDATE ON database_name.* TO 'role_name';

## 유저에 관련 Role 부여
GRANT 'role_name' TO 'user_name'@'host';

## Role 삭제
DROP ROLE 'role_name';

## Role에 대한 권한 확인
SHOW GRANTS FOR 'role_name';

 

오우... 유저에 권한을 부여하고 하는것보다 더 간단하다고 생각했다.

Role을 사용하면 팀으로 공통된 역할을 부여하는것이 가능할거라고 생각했다.

 

적용 Architecture

위 구성을 보면 설명은 아래와 같다.

  • ADMIN_ROLE은 말 그대로 DB 전체적인 권한
  • DATA_ROLE은 DB 에 DML / DDL 권한 및 DBA 수준의 역할을 부여
  • *_TEAM_ROLE은 팀마다 관리하는 DB.Table 별 DML 권한 부여
  • *_TEAM_READONLY_ROLE은 팀마다 관리하는 DB.Table 별 SELECT 권한 부여

이렇듯 Role 자체를 미리 만들어두면 유저별로 권한을 부여해주는 귀찮은 짓은 안해도 된다.

그럼? Role 관리는 어떻게 할까?

 

테라폼을 활용하자 (MYSQL Provider)

테라폼 + MYSQL Provider를 활용하여 Role Base로 관리하기

이 회사에 테라폼 마스터인 내가 있으니... 어떤것도 무섭지 않지

Role 자체에 대한 정의를 미리 만들어놓고 users.tf에다가 해당 값을 매핑시킨다면 크게 어려운것은 없었다

 

## provider.tf

terraform {
  required_providers {
    mysql = {
      source = "petoju/mysql"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.0"
    }
  }
}

variable "HOST" {
 
}

variable "DB_USER" {
  
}

variable "DB_PASSWORD" {

}

provider "mysql" {
  endpoint = "${var.HOST}:3306"
  username = var.DB_USER
  password = var.DB_PASSWORD
}

provider "aws" {
  profile = ########
  region  = "ap-northeast-2"
}

terraform {
  backend "s3" {
    bucket  = "shared-state"
    key     = "database/prd/prd-cluster/terraform.tfstate"
    region  = "ap-northeast-2"
    profile = #######
  }
}

 

 ## roles.tf
 
 ROLES = {
    ADMIN : {
      "%" : "ADMIN"
    },
    "STANDARD" : {
      "prod%" : "READ_ONLY",
      "prd%" : "READ_ONLY"
    },
    "DBA" : {
      "performance_schema" : "READ_ONLY"
    },
    "DATA" : {
      "prod%" : "ALL_DATA",
      "prd%" : "ALL_DATA"
    },
  }

  // DML (CRUD)
  TEAM_ROLES = {
    "REFUND" : {
      "refund.p" : "TEAM_DML",
      "refund.pV2" : "TEAM_DML",
      "refund.pLog" : "TEAM_DML",
      "refund.history" : "TEAM_DML",
      "refund.fail" : "TEAM_DML",
      "refund.status" : "TEAM_DML"
    },
    "CARE" : {},
    "OP" : {},
    "CORE" : {},
    "REFUND_READONLY" : {},
    "CARE_READONLY" : {},
    "OP_READONLY" : {},
    "CORE_READONLY" : {},    
  }

 

users.yml

user:
  display_name: user lee
  email: user@company_workspace.kr
  given_name: user
  family_name: lee
  group: developer
  role:
    shared:
      - developer-service
    dev:
      - zent-sso
  db:
    prd-database:
      - STANDARD ## Role
      - REFUND   ## Role

 

provider로 MYSQL을 정의하고

roles.tf에 관련된 Role을 정의한다

그리고 users.yml 을 정의 한후 yamldecode 메서드를 사용해서 기존 role과 매핑시켜주면 된다. (매핑하는 로직이 꽤 빡셀수 있음)

결과는 아래와 같다

Role 부여

유저자체가 가지는 권한에 대해서는 손쉽게 Role로써 부여가 가능하다.

또 이를 Terraform으로 한번더 추상화하니, 더 쉽게 관리가 가능해졌다.


 

반응형

+ Recent posts