파이썬 웹 서비스 만들기

11. 서버 관리에 필요한 정보 관리

영바이트 2020. 12. 2. 23:38

 

앞의 예제들에서 웹 서비스를 제공하기 위해서 DB, (외부) 이메일 서버를 사용하였다. DB와 이메일 서버는 웹 프로그램과는 별도의 프로그램으로서 이들 프로그램을 사용하기 위해 계정(account)을 생성하고 비밀번호를 입력해서 웹프로그램과 연결하였다.

 

앞서 진행했던 예제 프로젝트들의 최상위 패키지인 appmain 패키지의 설정 파일인 __init__.py 파일을 살펴보면 아래와 같이 서비스 제공에 필요한 비밀키, 다른 프로그램 계정 및 비밀번호가 그대로 들어있다.

 

appmain 패키지 설정파일

 

▶appmain/__init__.py

                                                ...
                                                
app.config['SECRET_KEY'] = 'd2eb5380841f5fdc4b70bb3e8be4a614'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://flaskweb:your_password@localhost:3306/flaskdb'

                                                ...
                                                
app.config['MAIL_USERNAME'] = 'YOUR_USERNAME'
app.config['MAIL_PASSWORD'] = 'YOUR_PASSWORD'

                                                ...

 

개발을 진행하다보면 백업backup, 협업 등을 위해 파일들을 git hub과 같은 외부 버전관리 시스템에 업로드하고 공유하는 일이 생기게된다. 이런 경로를 통해 서버 관리에 필수적인 중요한 정보가 외부로 유출되면 서버의 보안에 구멍이 생기게된다. 이번 편에서는 외부로 유출되어서는 안되는 중요한 정보들을 별도의 파일에 넣어서 관리하는 방법에 대해 살펴본다.

 


 

특별히 이론적으로 설명할 내용이 있는 주제는 아니기 때문에 어떻게 별도의 파일로 관리할 수 있는지 그 예를 보면서 이야기하도록 하겠다. 아래와 같이 새로운 프로젝트를 생성하고 가장 최신 예제인 08_reset_password 예제의 내용을 복사해서 가져온다(09_custom_error_pages 예제는 맞춤형 오류 페이지 기능에 대해서만 살펴보았던 예제였다).

 

그리고 appmain 패키지 바로 아래에 config.json, config.py 두 파일을 새로 생성하고 먼저 아래와 같이 DB, (외부) 메일서버 계정, 비밀번호와 같은 중요한 정보들을 config.json 파일 안에 파이썬 딕셔너리 형태로 저장한다.

 

프로젝트 config 파일들

 

▶appmain/config.json

{
  "SECRET_KEY": "d2eb5380841f5fdc4b70bb3e8be4a614",
  "DB_USERNAME": "flaskweb",
  "DB_PASSWORD": "your_password",
  "MAIL_USERNAME": "YOUR_USERNAME",
  "MAIL_PASSWORD": "YOUR_PASSWORD"
}

 

config.py 파일 안의 Config 클래스는 서버 관리에 필요한 내용이 담겨있는 파일인 config.json 파일을 읽어와서 클래스 변수에 저장한다. 즉, Config 클래스에서 읽어오는 config.json 파일을 외부 사용자가 접근할 수 없는 안전한 곳으로 옮기고 해당 파일의 경로(path)를 open 함수에 지정하면 Config 클래스는 설정에 필요한 정보들을 읽어올 수 있게된다.

 

▶appmain/config.py

import json

class Config:
    def __init__(self):
        #### 설정 파일 config.json을 읽어온다.
        with open('./PythonFlaskBlog/10_config_files/appmain/config.json') as cf:
            self.config = json.load(cf)

        #### 읽어온 설정 파일의 내용들을 클래스 변수들에 저장한다.
        self.SECRET_KEY = self.config.get("SECRET_KEY")
        self.DB_USERNAME = self.config.get("DB_USERNAME")
        self.DB_PASSWORD = self.config.get("DB_PASSWORD")
        self.MAIL_USERNAME = self.config.get("MAIL_USERNAME")
        self.MAIL_PASSWORD = self.config.get("MAIL_PASSWORD")

 

위 예제 코드에서 설정파일 config.json의 경로(path)에 PythonFlaskBlog라는 상위 디렉토리가 포함되어있다. 이 PythonFlaskBlog 디렉토리는 모든 예제 프로젝트들을 담고 있는 작업 디렉토리인데 스크립트를 실행하는 파이썬 번역기가 이 작업 디렉토리보다 한 단계 상위 디렉토리에서 실행되기 때문에 이 작업 디렉토리 PythonFlaskBlog까지 상대 경로에 포함시켰다.

 

작업디렉토리 - PythonFlaskBlog

 


 

서버 관리에 필요한 정보들을 appmain 패키지의 초기화 파일 appmain/__init__.py 파일에서 설정했었다. 이전 예제들에서 초기화 명령 코드에 계정 이름, 비밀 번호를 직접 기재했었던 형태를 수정하여 Config 클래스 객체를 생성하고 해당 객체로 부터 서버 관리에 필요한 정보들을 가져오도록 수정한다.

 

appmain 패키지 초기화 파일

 

수정되어야 하는 부분을 아래와 같이 나타내었다. 말 줄임표(...)로 생략된 부분은 기존 내용과 동일하다.

 

▶ appmain/__init__.py

from ...

#### 설정Config 클래스를 가져온다.
from appmain.config import Config

app = Flask(__name__)

#### 설정Config 클래스 객체를 생성한다.
cfg = Config()

#### 설정Config 클래스 객체 cfg의 변수를 이용해서 웹 서버에 필요한 설정을 한다.
app.config['SECRET_KEY'] = cfg.SECRET_KEY
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://' + \
                                        cfg.DB_USERNAME + \
                                        ':' + \
                                        cfg.DB_PASSWORD + \
                                        '@localhost:3306/flaskdb'

app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = cfg.MAIL_USERNAME
app.config['MAIL_PASSWORD'] = cfg.MAIL_PASSWORD

...

 

저장하고 실행하면 아래와 같이 웹 서버가 정상적으로 서비스를 제공하는 것을 확인할 수 있다.

 

웹 서버 실행 결과

 

서버 관리에 필요한 중요한 정보들을 별도 파일에 넣어 관리하는 방법에 대해 살펴보았다. 이렇게 별도 파일로 설정 정보들을 관리하고 프로젝트 디렉토리 밖의 안전한 위치에 파일을 보관하면(※ 예제에서는 학습의 편의를 위해 프로젝트 디렉토리 안에 보관하였다) 자칫 웹 서버 코드가 유출되더라도 보안 측면에서 중요한 정보까지 노출되는 사고를 방지할 수 있다.