모도리는 공부중

[DB 보안] db ↔ 애플리케이션 연결 SSL 구성 관련 (feat. ChatGPT) 본문

내 지식 정리/날것 그 자체

[DB 보안] db ↔ 애플리케이션 연결 SSL 구성 관련 (feat. ChatGPT)

공부하는 모도리 2025. 1. 7. 17:33
728x90
반응형

 

 

🤔

sslUse를 하고 싶다면 어떻게 돼?

 

🤖

MySQL에서 SSL을 사용하는 경우, 데이터베이스 연결 문자열에 추가적인 옵션을 설정하여 보안을 강화할 수 있습니다. SQLAlchemy와 MySQL 드라이버를 사용하여 SSL 연결을 구성하는 방법은 아래와 같습니다.


SSL을 위한 사전 준비

  1. MySQL 서버 설정:
    • MySQL 서버가 SSL 연결을 지원하도록 설정되어 있어야 합니다.
    • 필요한 인증서(클라이언트 인증서, 키, 서버 CA 인증서)를 준비하세요.
    예: MySQL 서버 설정 파일(my.cnf)에 SSL 관련 옵션이 추가되어 있어야 합니다.
  2. [mysqld] ssl-ca=/path/to/ca-cert.pem ssl-cert=/path/to/server-cert.pem ssl-key=/path/to/server-key.pem
  3. 인증서 파일 준비: 클라이언트 측에서 사용할 인증서를 준비하세요:
    • client-cert.pem: 클라이언트 인증서.
    • client-key.pem: 클라이언트 키.
    • ca-cert.pem: 서버의 CA 인증서.

SQLAlchemy를 사용한 SSL 설정

SSL을 사용하려면 SQLAlchemy의 연결 문자열에 SSL 옵션을 추가해야 합니다.

1. 기본 SSL 연결 설정

SSL을 활성화하려면 ssl 옵션을 추가하여 SSL 연결을 활성화할 수 있습니다. 아래는 기본적인 연결 문자열입니다.

DATABASE_URL = (
  "mysql+pymysql://user:password@localhost:3306/mydatabase"
  "?ssl_ca=/path/to/ca-cert.pem"
  "&ssl_cert=/path/to/client-cert.pem"
  "&ssl_key=/path/to/client-key.pem"
)

이렇게 하면 ssl_ca, ssl_cert, ssl_key 옵션을 통해 MySQL 서버와 안전하게 통신합니다.


2. SSL 옵션 추가

pymysql은 ssl 파라미터로 SSL 인증서를 받을 수 있습니다. SQLAlchemy로 이를 설정하려면 create_engine을 사용할 때 connect_args를 통해 추가 옵션을 전달합니다.

from sqlalchemy.ext.asyncio import create_async_engine

DATABASE_URL = "mysql+aiomysql://user:password@localhost:3306/mydatabase"

# SSL 인증서 경로
ssl_args = {
  "ssl": {
    "ca": "/path/to/ca-cert.pem",
    "cert": "/path/to/client-cert.pem",
    "key": "/path/to/client-key.pem"
  }
}

# Async SQLAlchemy 엔진 생성
engine = create_async_engine(DATABASE_URL, connect_args=ssl_args)

3. 비동기(Async) SSL 설정

aiomysql 드라이버를 사용할 때도 비슷한 방식으로 connect_args에 ssl 옵션을 추가하면 됩니다.

from sqlalchemy.ext.asyncio import create_async_engine

DATABASE_URL = "mysql+aiomysql://user:password@localhost:3306/mydatabase"

# SSL 설정
engine = create_async_engine(
  DATABASE_URL,
  connect_args={
    "ssl": {
      "ca": "/path/to/ca-cert.pem",
      "cert": "/path/to/client-cert.pem",
      "key": "/path/to/client-key.pem"
    }
  }
)

인증서 없이 SSL 연결 (Optional)

MySQL 서버가 인증서를 요구하지 않고 SSL을 사용하는 경우 ssl_mode 옵션을 설정할 수 있습니다.

예: 인증서 없이 SSL을 강제하려면 ssl_mode=REQUIRED를 추가합니다.

DATABASE_URL = (
  "mysql+pymysql://user:password@localhost:3306/mydatabase"
  "?ssl_mode=REQUIRED"
)

전체 코드 예제

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "mysql+aiomysql://user:password@localhost:3306/mydatabase"

# SSL 설정
ssl_args = {
  "ssl": {
    "ca": "/path/to/ca-cert.pem",
    "cert": "/path/to/client-cert.pem",
    "key": "/path/to/client-key.pem"
  }
}

# 비동기 엔진 생성
engine = create_async_engine(DATABASE_URL, connect_args=ssl_args)

# 세션 팩토리 생성
async_session = sessionmaker(
  bind=engine,
  class_=AsyncSession,
  expire_on_commit=False
)

# 데이터베이스 의존성
async def get_db():
  async with async_session() as session:
    yield session

주의 사항

  1. MySQL 서버와 클라이언트 간 SSL 설정이 맞아야 연결됩니다.
    • 서버에서 요구하는 인증서를 정확히 제공해야 합니다.
  2. 퍼포먼스 고려:
    • SSL 연결은 보안을 강화하지만 약간의 성능 저하가 발생할 수 있습니다.
  3. 드라이버 지원:
    • 대부분의 MySQL 드라이버(pymysql, aiomysql, mysqlclient)는 SSL을 지원하지만, 일부 드라이버에서는 설정 방식이 다를 수 있습니다.

추가 질문이나 세부적인 설정이 필요하면 말씀해주세요!

 


🤔

필요한 인증서(클라이언트 인증서, 키, 서버 CA 인증서)를 준비는 어떻게 해?

 

🤖

MySQL이나 MariaDB의 SSL 인증서를 준비하는 방법은 서버 설정과 클라이언트 연결 방식에 따라 다르지만, 일반적으로 다음 단계를 따라 인증서를 생성하고 사용할 수 있습니다. 아래 과정은 OpenSSL을 이용한 인증서 생성 과정을 설명합니다.


1. OpenSSL 설치

OpenSSL은 인증서를 생성하고 관리하는 데 필요한 도구입니다.

  • 리눅스/우분투:
  • sudo apt update sudo apt install openssl
  • macOS: OpenSSL이 기본 설치되어 있습니다. 없으면 Homebrew로 설치:
  • brew install openssl
  • Windows: OpenSSL 공식 사이트에서 다운로드하여 설치.

2. 인증 기관(CA) 인증서 생성

먼저, 자체 서명된 인증 기관(CA)을 생성해야 합니다. 이는 MySQL 서버와 클라이언트가 신뢰할 수 있는 CA로 작동합니다.

2-1. CA 개인 키 생성

openssl genrsa 2048 > ca-key.pem

2-2. CA 인증서 생성

openssl req -new -x509 -nodes -days 3650 \
  -key ca-key.pem \
  -out ca-cert.pem \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=MySQL-CA"

여기서 -subj는 인증서에 들어갈 정보를 지정합니다.

  • C=US: 국가 코드 (예: 대한민국은 KR).
  • ST=State: 주/도 이름.
  • L=City: 도시 이름.
  • O=Organization: 조직 이름.
  • CN=MySQL-CA: 공통 이름(Common Name).

3. 서버 인증서 및 키 생성

MySQL 서버에서 사용할 인증서와 키를 생성합니다.

3-1. 서버 키 생성

openssl genrsa 2048 > server-key.pem

3-2. 서버 인증서 서명 요청(CSR) 생성

openssl req -new -key server-key.pem -out server-req.pem \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=mysql-server"

3-3. CA로 서버 인증서 서명

openssl x509 -req -in server-req.pem -days 3650 \
  -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem

4. 클라이언트 인증서 및 키 생성

MySQL 클라이언트가 사용할 인증서와 키를 생성합니다.

4-1. 클라이언트 키 생성

openssl genrsa 2048 > client-key.pem

4-2. 클라이언트 인증서 서명 요청(CSR) 생성

openssl req -new -key client-key.pem -out client-req.pem \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=mysql-client"

4-3. CA로 클라이언트 인증서 서명

openssl x509 -req -in client-req.pem -days 3650 \
  -CA ca-cert.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem

5. MySQL 서버에 SSL 설정

MySQL 서버 설정 파일(my.cnf 또는 my.ini)에 SSL 관련 설정을 추가합니다.

5-1. 인증서 파일 배치

인증서를 MySQL 서버가 접근할 수 있는 경로에 저장하세요.

  • ca-cert.pem: CA 인증서.
  • server-cert.pem: 서버 인증서.
  • server-key.pem: 서버 키.

5-2. my.cnf 설정

[mysqld]
ssl-ca=/path/to/ca-cert.pem
ssl-cert=/path/to/server-cert.pem
ssl-key=/path/to/server-key.pem

5-3. MySQL 재시작

sudo systemctl restart mysql

6. MySQL 클라이언트에 SSL 설정

클라이언트도 인증서를 사용하여 서버에 연결해야 합니다.

6-1. MySQL 명령줄에서 SSL 테스트

mysql -u user -p --ssl-ca=/path/to/ca-cert.pem \
  --ssl-cert=/path/to/client-cert.pem \
  --ssl-key=/path/to/client-key.pem

7. SQLAlchemy에서 SSL 사용

인증서 파일을 SQLAlchemy 연결 설정에 추가합니다.

DATABASE_URL = (
  "mysql+pymysql://user:password@localhost:3306/mydatabase"
  "?ssl_ca=/path/to/ca-cert.pem"
  "&ssl_cert=/path/to/client-cert.pem"
  "&ssl_key=/path/to/client-key.pem"
)

8. 인증서 상태 확인

MySQL 서버에서 현재 SSL 상태를 확인하려면 다음 명령을 실행합니다.

SHOW VARIABLES LIKE 'have_ssl';

결과가 YES라면 SSL 설정이 제대로 작동 중입니다.


참고

  1. 공인 인증서 사용: 자체 서명된 CA 대신 공인된 CA(예: Let's Encrypt, DigiCert) 인증서를 사용하는 경우 서버 설정만 변경하면 됩니다.
  2. 인증서 관리: 인증서 만료 기간(days)을 적절히 설정하고 만료 전에 갱신해야 합니다.

궁금한 점이 있거나 추가적인 지원이 필요하면 말씀해주세요!

 


 

🤔

ssh 접속할 때 id/pw 방법 대신 pem키로 접속하는 방식과 유사해보여. 하지만 여기서는 id/pw도 여전히 입력해야하고 인증서 만료 기간 설정도 필요해보이네?

 

🤖

맞습니다! MySQL에서 SSL 인증서를 이용한 연결 방식은 SSH의 id/pw 대신 .pem 키로 접속하는 방식과 개념적으로 유사하지만, 몇 가지 차이점과 추가적인 요구사항이 있습니다. 이를 비교하면서 차이점을 정리해 보겠습니다.


유사점: SSH와 MySQL SSL 연결 방식

  1. 보안 강화:
    • 둘 다 네트워크를 통해 전송되는 데이터를 암호화하여 안전하게 통신합니다.
    • 중간자 공격(Man-in-the-Middle Attack) 등을 방지하기 위해 인증서 또는 를 사용합니다.
  2. 클라이언트와 서버 간 인증:
    • SSH에서 .pem 키를 사용하여 클라이언트가 인증되듯, MySQL SSL에서도 클라이언트 인증서를 통해 서버가 클라이언트를 인증할 수 있습니다.
    • MySQL SSL에서는 서버 역시 인증서를 통해 클라이언트에게 자신의 신원을 인증합니다.
  3. 접속 정보 추가 필요:
    • SSH: .pem 키만 있으면 서버에 연결 가능(추가적인 ID/PW 필요 없음).
    • MySQL SSL: username/password를 여전히 사용하지만, 인증서를 통해 추가적인 보안을 제공합니다.

차이점: MySQL SSL vs SSH

1. ID/PW 사용 여부

  • SSH: .pem 키만 사용하면 id/pw 없이 접속 가능.
    → 이는 SSH 서버가 키 기반 인증만 허용하도록 설정된 경우 가능합니다.
  • MySQL SSL: 인증서가 있더라도 여전히 **id/pw**를 요구합니다. → MySQL에서는 인증서만으로 인증하는 방식(user@host IDENTIFIED VIA SSL)도 가능하지만 일반적으로는 ID와 비밀번호를 조합하여 사용합니다.

2. 인증서 만료 관리

  • SSH: .pem 키는 기본적으로 만료 기간이 없으며, 키 파일 자체가 손상되거나 삭제되지 않는 이상 유효합니다.
    • 추가로 만료를 설정하려면 키 관리 시스템(e.g., AWS EC2 Key Pair)을 통해 만료 주기를 설정해야 합니다.
  • MySQL SSL:
    • CA 인증서, 서버 인증서, 클라이언트 인증서유효 기간을 설정해야 합니다.
    • 만료된 인증서는 연결에 실패하므로 주기적으로 갱신해야 합니다.
    • 예를 들어, 인증서를 생성할 때 -days 옵션으로 1년(365일), 10년(3650일)과 같이 유효 기간을 설정합니다.
      openssl req -new -x509 -nodes -days 3650 ...
      

3. 접근 방식

  • SSH:
    • 서버에 접속하기 전에 .pem 키를 서버와 교환하거나 등록해야 합니다.
    • 접속 시 클라이언트는 키 파일을 사용하여 서버에 인증을 요청합니다.
      ssh -i /path/to/private-key.pem user@hostname
      
  • MySQL SSL:
    • MySQL 서버는 클라이언트와 통신 시 인증서를 요구합니다.
    • 클라이언트는 ID/PW와 함께 인증서를 제공하여 인증 절차를 완료합니다.
      mysql -u user -p --ssl-ca=/path/to/ca-cert.pem \
        --ssl-cert=/path/to/client-cert.pem \
        --ssl-key=/path/to/client-key.pem
      

왜 MySQL SSL은 ID/PW를 요구하는가?

MySQL SSL 연결은 단순히 보안 통신(암호화된 채널)을 제공하는 것이 주목적이며, 기본 인증(ID/PW) 과 함께 작동하는 것이 일반적입니다. 다만, 필요에 따라 클라이언트 인증서 기반 인증만 사용하도록 구성할 수도 있습니다.

인증서 기반 인증만 사용하기:

MySQL에서 IDENTIFIED WITH 'sha256_password' REQUIRE X509를 설정하면 클라이언트 인증서만으로 인증을 수행할 수 있습니다.
이렇게 설정하면 ID/PW 없이 인증서만으로 연결 가능합니다.

설정 예시:

  1. MySQL 사용자 계정 설정:
  2. CREATE USER 'ssl_user'@'%' IDENTIFIED WITH 'sha256_password' REQUIRE X509; GRANT ALL PRIVILEGES ON mydatabase.* TO 'ssl_user'@'%'; FLUSH PRIVILEGES;
  3. 클라이언트 접속:
  4. mysql --ssl-ca=/path/to/ca-cert.pem \ --ssl-cert=/path/to/client-cert.pem \ --ssl-key=/path/to/client-key.pem

MySQL SSL 설정의 의의

  1. ID/PW와 인증서를 조합하여 이중 인증 구현:
    • 인증서가 추가적인 보안 계층을 제공합니다.
    • 비밀번호가 유출되어도 인증서가 없으면 접속할 수 없습니다.
  2. 유효 기간으로 보안 강화:
    • 인증서가 만료되면 재발급해야 하므로 보안이 강화됩니다.
    • 장기적으로 관리 비용이 증가할 수 있지만, 민감한 데이터를 다루는 경우에는 필수적입니다.

정리

  • SSH 키 기반 인증은 "키 파일로 사용자 인증"을 대체하는 방식이고, MySQL SSL은 기본 인증에 추가적인 보안 계층(암호화 및 인증)을 제공합니다.
  • MySQL SSL에서 ID/PW를 대체하려면 인증서 기반 인증만 사용하도록 MySQL 설정을 변경해야 합니다.
  • MySQL SSL의 인증서는 유효 기간을 가지고 있으므로 갱신 관리를 철저히 해야 합니다.

추가적으로 SSL만으로 인증을 구성하거나 설정 관리에 대해 궁금한 점이 있다면 언제든지 알려주세요!

 


 

🤔

이러한 접속 방식은 mysql에만 한정돼? 아니면 다른 db도 마찬가지야?

 

🤖

SSL을 사용한 접속 방식은 MySQL에 한정된 것이 아니며, 대부분의 주요 데이터베이스(DBMS)에서도 동일하거나 유사한 방식으로 지원됩니다. SSL/TLS는 네트워크를 통해 데이터를 안전하게 암호화하고 클라이언트-서버 간 신뢰를 보장하기 위한 표준 보안 프로토콜이기 때문에 다양한 데이터베이스에서 채택하고 있습니다.


주요 데이터베이스와 SSL 지원 비교

1. MySQL/MariaDB

  • SSL/TLS를 통한 연결 지원.
  • 인증서(CA, 서버, 클라이언트)로 양방향 인증 가능.
  • ID/PW 인증과 함께 사용하거나, 인증서만으로 인증 가능.
  • 설정 방식:
    • 서버: ssl-ca, ssl-cert, ssl-key 옵션으로 설정.
    • 클라이언트: --ssl-* 옵션 또는 ORM/드라이버를 통해 설정.

2. PostgreSQL

PostgreSQL도 SSL/TLS를 통해 데이터 암호화를 지원하며, 인증서를 사용한 클라이언트-서버 인증이 가능합니다.

설정 방식:

  1. 서버 설정 (postgresql.conf):
  2. ssl = on ssl_cert_file = '/path/to/server-cert.pem' ssl_key_file = '/path/to/server-key.pem' ssl_ca_file = '/path/to/ca-cert.pem'
  3. 클라이언트 연결:
    • psql CLI:
      psql "sslmode=verify-full sslrootcert=/path/to/ca-cert.pem"
      
    • Python에서 psycopg2:
      conn = psycopg2.connect(
        dbname="mydb",
        user="user",
        password="password",
        host="localhost",
        port=5432,
        sslmode="verify-full",
        sslrootcert="/path/to/ca-cert.pem"
      )
      

SSL 모드:

PostgreSQL은 SSL 모드를 세부적으로 제어할 수 있습니다:

  • disable: SSL 사용 안 함.
  • allow: SSL을 사용할 수도 있지만 필수는 아님.
  • prefer: 가능하면 SSL 사용.
  • require: SSL 필수.
  • verify-ca: SSL 인증서 확인.
  • verify-full: 인증서와 호스트 이름 확인.

3. Oracle Database

Oracle Database도 SSL을 통해 보안 연결을 제공합니다.

설정 방식:

  1. 서버에 인증서를 설치하고 SSL/TLS를 활성화합니다.
    • sqlnet.ora 파일에서 SSL 활성화:
      SQLNET.AUTHENTICATION_SERVICES = (TCPS)
      SSL_SERVER_CERT_DN = "CN=server-name, OU=unit, O=org, C=country"
      
  2. 클라이언트 연결:
    • tnsnames.ora에 SSL 설정 추가:
      mydb=
        (DESCRIPTION=
          (ADDRESS=(PROTOCOL=TCPS)(HOST=mydbhost)(PORT=2484))
          (CONNECT_DATA=(SERVICE_NAME=mydb))
        )
      

4. Microsoft SQL Server

Microsoft SQL Server는 SSL/TLS를 통해 암호화된 연결을 지원합니다. 클라이언트 인증서를 설정하거나 SQL Server Management Studio(SSMS) 또는 애플리케이션에서 SSL 옵션을 설정할 수 있습니다.

설정 방식:

  1. 서버:
    • SQL Server Configuration Manager에서 SSL/TLS 활성화.
    • 인증서를 설치하고 사용할 포트를 설정.
  2. 클라이언트:
    • ODBC, ADO.NET 등에서 Encrypt=True 및 TrustServerCertificate=True 옵션 사용.
    • Python에서 pyodbc:
      conn = pyodbc.connect(
        "DRIVER={ODBC Driver 17 for SQL Server};"
        "SERVER=server_name;"
        "DATABASE=mydb;"
        "UID=user;"
        "PWD=password;"
        "Encrypt=yes;"
        "TrustServerCertificate=no;"
      )
      

5. MongoDB

MongoDB도 SSL/TLS를 지원하며, 인증서를 통한 보안 연결이 가능합니다.

설정 방식:

  1. 서버:
    • mongod.conf에서 TLS/SSL 설정:
      net:
        ssl:
          mode: requireSSL
          PEMKeyFile: /path/to/server.pem
          CAFile: /path/to/ca.pem
      
  2. 클라이언트:
    • CLI:
      mongo --ssl --sslCAFile /path/to/ca.pem \
            --sslPEMKeyFile /path/to/client.pem \
            --host mydbhost
      
    • Python에서 pymongo:
      from pymongo import MongoClient
      
      client = MongoClient(
        "mongodb://mydbhost:27017",
        ssl=True,
        ssl_ca_certs="/path/to/ca.pem",
        ssl_certfile="/path/to/client.pem",
        ssl_keyfile="/path/to/client-key.pem"
      )
      

6. Redis

Redis도 SSL/TLS를 지원합니다(기본적으로 암호화되지 않은 통신 방식).

설정 방식:

  1. Redis 서버에서 stunnel을 통해 SSL을 활성화하거나 Redis Enterprise를 사용하여 직접 SSL 설정.
  2. 클라이언트 연결:
    • Python에서 redis-py:
      import redis
      
      conn = redis.StrictRedis(
        host="mydbhost",
        port=6379,
        password="mypassword",
        ssl=True,
        ssl_ca_certs="/path/to/ca-cert.pem"
      )
      

공통점

  1. SSL/TLS를 지원:
    • 데이터 암호화를 통해 전송 중 데이터 보호.
    • 클라이언트-서버 간 신뢰를 보장.
  2. 인증서 사용 가능:
    • 클라이언트와 서버 모두 인증서를 통해 상호 인증 수행 가능.
  3. 추가 보안 옵션 제공:
    • 암호화 수준 설정, 인증서 검증 강화, 호스트 이름 확인 등.

결론

  • MySQL 외에도 PostgreSQL, Oracle, MSSQL, MongoDB, Redis 등 대부분의 데이터베이스가 SSL/TLS 및 인증서를 통한 보안 연결을 지원합니다.
  • MySQL과 마찬가지로 다른 데이터베이스도 ID/PW인증서 기반 인증을 조합하거나 인증서만으로 인증하는 방식으로 구성할 수 있습니다.
  • 따라서, SSL 인증 기반 접근은 데이터베이스 종류와 상관없이 보편적인 방식이라고 볼 수 있습니다.

어떤 데이터베이스에 적용할 계획인지 알려주시면, 해당 DB에 맞는 구체적인 설정 방법을 도와드릴게요!

728x90
반응형
Comments