Taeyoung Kim

Cloud & Platform

Azure 계정 보안, 스토리지 및 Docker 활용 가이드

Azure 계정 보안, 스토리지 및 Docker 활용 가이드 학습 내용을 정리한 백필 노트입니다.

이 글은 2025년 학습 기록을 블로그 형식으로 정리한 백필 노트입니다.


1. Azure 계정 보안 강화

1.1. 다단계 인증(MFA) 설정

OTP(One-Time Password)를 사용하여 계정 보안을 강화합니다. OTP는 일정 시간 동안만 유효한 임시 비밀번호로, 로그인 시 추가 인증 수단으로 사용됩니다.

1.1.1. 테넌트 관리 계정에 적용

  1. MFA 활성화:
    • Azure Portal에서 ID > 사용자 > 모든 사용자로 이동합니다.
    • MFA를 적용할 사용자 계정을 클릭한 후, 상단의 'MFA 사용' 버튼을 누릅니다.
  2. 사용자 설정 (최초 로그인 시):
    • 활성화 후 해당 계정으로 시크릿 모드에서 새로 로그인하면 2단계 인증 설정 화면이 나타납니다.
    • Google Authenticator와 같은 OTP 앱을 스마트폰에 설치합니다.
    • 앱에서 'QR 코드 스캔'을 선택하고 화면에 표시된 QR 코드를 스캔합니다.
    • 앱에 생성된 6자리 코드를 입력하여 인증을 완료합니다.
    • 이후 로그인 또는 중요한 작업 수행 시 OTP 인증이 요구됩니다.

[참고] MFA 인증 해제 방법

MFA를 설정한 동일한 사용자 관리 페이지에서 해당 사용자를 선택하고 'MFA 사용 안 함' 버튼을 클릭하여 비활성화할 수 있습니다.

1.1.2. 마이크로소프트 개인 계정에 적용

  1. 설정 페이지 이동:
    • Azure Portal 우측 상단의 프로필 아이콘을 클릭하여 **'Microsoft 계정 보기'**로 이동합니다.
    • 보안 > 로그인 방법 관리 페이지로 이동합니다.
  2. 2단계 인증 활성화:
    • '추가 보안' 섹션에서 **'2단계 인증'**을 **'켜기'**로 설정합니다.
    • 이후 과정은 테넌트 관리 계정과 동일하게 Google Authenticator 앱으로 QR 코드를 스캔하여 설정합니다.

[참고] 2단계 인증 해제 방법

동일한 '추가 보안' 섹션에서 **'2단계 인증'**을 **'비활성화'**하여 해제할 수 있습니다.

1.2. 비밀번호 정책 설정 (프리미엄 계정)

Microsoft Entra ID에서 조직의 비밀번호 정책을 설정하여 보안을 강화할 수 있습니다. (무료 계정에서는 제한됨)

  1. Entra 관리 센터 이동: Azure Portal에서 Microsoft Entra ID를 검색하고 'Go to Microsoft Entra' 링크를 클릭합니다.
  2. 암호 보호 설정:
    • 보호 > 인증 방법 > 암호 보호로 이동합니다.
    • 여기서 계정 잠금 임계값(로그인 실패 허용 횟수), 사용자 지정 금지 암호 목록 등을 설정할 수 있습니다.
  3. 알림 설정:
    • 보호 > 암호 재설정 > 알림 메뉴에서 암호 재설정 시 사용자나 관리자에게 알림을 보내도록 구성할 수 있습니다.

2. Azure 사용자 및 그룹 관리 (RBAC)

사용자를 그룹으로 묶고, 그룹에 역할을 할당하여 리소스 접근 권한을 효율적으로 관리(RBAC: Role-Based Access Control)합니다.

2.1. 사용자 및 그룹 생성

  1. 새 사용자 만들기:
    • Microsoft Entra 관리 센터에서 ID > 사용자 > 모든 사용자 > 새 사용자 만들기를 선택합니다.
    • 사용자 계정 이름: test-user
    • 암호: Optional12!@ (자동 생성 해제)
  2. 새 그룹 만들기:
    • Azure Portal에서 Groups로 이동하여 'New Group'을 클릭합니다.
    • Group type: Security (리소스 접근 권한 관리용)
    • Group name: test-group
  3. 그룹에 멤버 추가:
    • 생성된 test-group으로 이동하여 Manage > Members > Add members를 선택합니다.
    • test-user를 검색하여 그룹에 추가합니다.

💡 불필요한 계정 정리

사용하지 않는 계정은 보안 위협이 될 수 있으므로 반드시 삭제하거나 비활성화해야 합니다. 이는 Azure 보안 모범 사례에서 강조하는 중요한 항목입니다.

2.2. 그룹에 권한 부여 및 확인

  1. 테스트용 리소스 그룹 생성:
    • Azure Portal에서 '리소스 그룹'으로 이동하여 test-rg라는 이름의 리소스 그룹을 생성합니다.
  2. 역할 할당:
    • 생성된 test-rg 리소스 그룹의 액세스 제어(IAM) > 추가 > 역할 할당 추가로 이동합니다.
    • 역할: 기여자(Contributor) 선택 (리소스 생성/수정/삭제 가능, 권한 할당 불가)
    • 구성원: test-group을 선택하여 역할을 할당합니다.
  3. 권한 확인:
    • test-user 계정(test-user@<계정_이메일>.onmicrosoft.com)으로 Azure Portal에 새로 로그인합니다.
    • 로그인 시 암호 변경 및 MFA(OTP) 설정이 강제됩니다.
    • '리소스 그룹' 메뉴로 이동하면 test-rg만 표시되고 접근 가능한 것을 확인할 수 있습니다.
    • test-rg 내에서는 가상 머신 등 리소스 생성이 가능하지만, 다른 리소스 그룹을 새로 만들거나 접근하는 것은 불가능합니다.

3. Azure Storage 활용

3.1. 스토리지 계정 생성

  • 리소스 그룹: sa-rg (신규)
  • 스토리지 계정 이름: storagecloud001 (전역적으로 고유해야 함)
  • 중복도: LRS(로컬 중복 스토리지)

3.2. Blob 컨테이너 사용 (객체 스토리지)

  1. 컨테이너 생성: storagecloud001 계정 내 데이터 스토리지 > 컨테이너에서 blob이라는 이름의 컨테이너를 생성합니다.
  2. 파일 업로드: 생성된 blob 컨테이너에 파일을 업로드합니다.
  3. 외부 공개 설정:
    • 설정 > 구성에서 **'Blob 익명 액세스 허용'**을 **'사용'**으로 변경합니다.
    • blob 컨테이너의 '액세스 수준 변경'에서 **'Container(컨테이너, Blob에 대한 익명 읽기 액세스)'**를 선택합니다.
    • 이제 각 파일의 URL을 통해 외부에서 직접 파일에 접근할 수 있습니다.
    • 주의: ?comp=list 파라미터를 URL에 추가하면 컨테이너 내 모든 파일 목록이 노출될 수 있으므로, 보안을 위해 CDN 등을 앞에 두는 것이 좋습니다.

3.3. 파일 공유(File Share) 생성 및 연결 (NAS)

여러 VM에서 공유하여 사용할 수 있는 네트워크 드라이브를 구성합니다.

  1. File Share 생성: storagecloud001 계정 내 파일 공유에서 share라는 이름의 파일 공유를 생성합니다.
  2. 테스트용 VM 생성: sa-rg 리소스 그룹에 linux VM(SSH 허용)과 window VM(RDP 허용)을 각각 생성합니다. (사용자 이름: azureuser)
  3. Windows VM에 연결 (Z: 드라이브):
    • share 파일 공유의 '연결' 메뉴에서 Windows용 연결 스크립트를 복사합니다.
    • window VM에 RDP로 접속하여 PowerShell(관리자)을 열고 복사한 스크립트를 실행합니다.
    • 탐색기에서 Z: 드라이브가 마운트된 것을 확인할 수 있습니다.
  4. Linux VM에 연결 (/media/share):
    • '연결' 메뉴에서 Linux용 연결 스크립트를 복사합니다.
    • linux VM에 SSH로 접속하여 복사한 스크립트를 실행합니다.
    • /media/share 디렉터리가 마운트되며, ls -al /media/share 명령어로 Windows VM에서 업로드한 파일이 보이는지 확인합니다.

3.4. 테이블(Table) 생성 및 사용 (NoSQL)

  1. 테이블 생성: storagecloud001 계정 내 테이블에서 table이라는 이름의 테이블을 생성합니다.
  2. System ID(Managed Identity) 설정:
    • linux VM 설정에서 ID > 시스템 할당을 **'켬'**으로 설정하여 VM에 고유 ID를 부여합니다.
  3. 권한 부여:
    • storagecloud001 계정의 액세스 제어(IAM)에서 역할 할당을 추가합니다.
    • 역할: 저장소 테이블 데이터 기여자
    • 구성원: linux VM의 시스템 할당 ID를 선택합니다.
  4. Python 스크립트로 데이터 조작:
    • linux VM에 접속하여 필요한 Python 라이브러리를 설치합니다.Bash

      sudo su
      apt update && apt install python3-pip -y
      pip3 config set global.break-system-packages true
      pip3 install azure-data-tables azure.identity
      
    • 아래 내용으로 app.py 파일을 생성하고 실행하여 테이블에 데이터를 생성, 조회, 삭제하는 작업을 수행합니다. 스크립트는 VM에 부여된 System ID 권한을 자동으로 사용하여 인증합니다.Python

      # app.py (전체 코드는 원본 메모 참조)
      # ...
      credential = DefaultAzureCredential() # System ID 권한 가져오기
      storage_name = "storagecloud001" # 본인의 스토리지 계정 이름
      table_name="table"
      # ... (엔터티 생성, 쿼리, 삭제 코드)
      
    • IAM에서 부여한 역할을 제거하면 스크립트 실행 시 권한 오류가 발생합니다.

3.5. 스토리지 계정 보안 설정 (CIS 벤치마크 기반)

  • 보안 전송 필요: 활성화 (기본값) - HTTPS 통신 강제
  • 최소 TLS 버전: 1.2로 설정 (기본값) - 취약한 구버전 프로토콜 차단
  • 인프라 암호화: 활성화 (기본값) - 데이터 센터 수준의 이중 암호화
  • 액세스 키 관리: 주기적으로 키를 교체(재생성)하고, 교체 알림을 활성화하는 것이 권장됩니다.
  • SAS 키 관리: SAS 토큰 생성 시 만료 시간을 짧게(예: 1시간 이내) 설정하여 토큰 유출 시 피해를 최소화합니다.
  • 공용 액세스 차단: 기본 네트워크 액세스 규칙을 '거부'로 설정하고, 필요한 경우에만 프라이빗 엔드포인트를 사용하여 내부망에서만 접근하도록 구성합니다.
  • 일시 삭제: 활성화 (기본값) - 실수로 삭제된 Blob을 복구할 수 있도록 설정합니다.
  • 감사 로그 활성화: 진단 설정을 통해 읽기/쓰기/삭제 작업에 대한 로그를 별도의 스토리지 계정에 저장하여 추적 및 감사를 수행합니다.

3.6. Front Door를 통한 안전한 Blob Storage 서비스

외부에 직접 Blob Storage를 노출하는 대신, Azure Front Door(Premium)를 사용하여 Private Link로 안전하게 연결하고 CDN, WAF 등의 부가 기능을 활용합니다.

  1. Blob Storage 준비: 정적 웹사이트용 스토리지 계정(static-website-username) 및 컨테이너(html)를 생성하고 index.html을 업로드합니다.
  2. Private Link 구성: 스토리지 계정의 '네트워킹' 설정에서 **'공용 액세스'를 '사용 안 함'**으로 변경하고, 프라이빗 엔드포인트를 생성하여 내부 네트워크를 구성합니다.
  3. Front Door (Premium) 구성:
    • Front Door 생성 시 원본(Origin)으로 Blob Storage를 선택하고 '프라이빗 링크'를 활성화합니다.
    • Front Door가 프라이빗 엔드포인트 생성을 자동으로 요청하고 승인 대기 상태가 됩니다.
    • 스토리지 계정의 프라이빗 엔드포인트 연결 설정에서 해당 요청을 승인합니다.
  4. 결과: 이제 스토리지 계정은 외부에서 직접 접근할 수 없으며, 오직 Front Door에서 제공하는 도메인을 통해서만 안전하게 콘텐츠에 접근할 수 있습니다.

3.7. 스토리지 리소스 정리

리소스 그룹 삭제 시 **잠금(Lock)**이나 Recovery Services 자격 증명 모음(Vault) 때문에 실패할 수 있습니다.

  1. 잠금 해제: 삭제하려는 리소스에 잠금이 설정되어 있다면 해당 리소스의 '잠금' 메뉴에서 먼저 해제합니다.
  2. 자격 증명 모음 삭제: Vault는 별도로 삭제해야 합니다. Vault 삭제 메뉴에서 제공하는 PowerShell 스크립트를 다운로드하여 Cloud Shell에서 실행하면 관련 종속성과 함께 깨끗하게 삭제됩니다.
  3. 리소스 그룹 삭제: 위 두 가지 조치 후 리소스 그룹을 다시 삭제하면 정상적으로 정리됩니다.

4. Azure VM에서 Docker 사용하기

4.1. Docker 환경 구성

  1. VM 생성: docker 리소스 그룹에 docker라는 이름의 Ubuntu VM을 생성합니다. (인바운드 포트: 80, 443, 22)

  2. Docker 설치: VM에 SSH로 접속하여 아래 명령어를 실행합니다.Bash

    sudo su
    sudo apt update && sudo apt install docker.io -y
    
  3. 설치 확인: docker info 명령어로 Docker 엔진 정보를 확인합니다.

4.2. Docker 기본 사용법

  1. 이미지 검색 및 다운로드:

    • Docker Hub에서 nginx 이미지를 검색합니다.
    • docker pull nginx:1.28.0-alpine-slim 명령어로 특정 버전의 이미지를 다운로드합니다.
    • docker images로 다운로드된 이미지 목록을 확인합니다.
  2. 컨테이너 생성 및 실행: docker run 명령어로 이미지를 컨테이너로 실행합니다.Bash

    # 호스트 80 포트 -> 컨테이너 80 포트로 연결
    docker run -d -p 80:80 --name nx nginx:1.28.0-alpine-slim
    # 호스트 81 포트 -> 컨테이너 80 포트로 연결
    docker run -d -p 81:80 --name nx81 nginx:1.28.0-alpine-slim
    
    • d: 백그라운드 실행
    • p: 포트 포워딩 (호스트:컨테이너)
    • -name: 컨테이너 이름 지정

4.3. 컨테이너 상세 정보 확인 및 관리

  • 실행 중인 컨테이너 확인: docker ps -a (정지된 컨테이너 포함)
  • 상세 정보 확인: docker inspect <이미지/컨테이너 이름>
    • 이를 통해 이미지의 구성(Config), 레이어(Layers), 컨테이너의 네트워크 설정(IP 주소, 게이트웨이), 파일 시스템 경로(MergedDir) 등 상세 정보를 파악할 수 있습니다.
  • 컨테이너 라이프 사이클:
    • docker create: 생성
    • docker start: 시작
    • docker stop: 중지
    • docker rm: 삭제
  • 유용한 명령어:
    • 로그 보기: docker logs <컨테이너 이름>
    • 내부 명령어 실행: docker exec -it <컨테이너 이름> sh
    • 파일 복사: docker cp <호스트 경로> <컨테이너>:<내부 경로> (호스트→컨테이너) 또는 docker cp <컨테이너>:<내부 경로> <호스트 경로> (컨테이너→호스트)

4.4. 연습 문제: Jenkins 컨테이너 배포

  1. 이미지 다운로드: docker pull jenkins/jenkins:lts-jdk17

  2. 컨테이너 실행: docker inspect로 노출된 포트(8080)를 확인하고 실행합니다.Bash

    docker run -d -p 80:8080 --name jk jenkins/jenkins:lts-jdk17
    
  3. 초기 비밀번호 확인: Jenkins 웹 페이지에 접속하면 초기 비밀번호 경로가 안내됩니다. 아래 두 방법 중 하나로 비밀번호를 확인하여 로그인합니다.Bash

    # 방법 1: 로그 확인
    docker logs jk
    # 방법 2: 파일 내용 확인
    docker exec jk cat /var/jenkins_home/secrets/initialAdminPassword
    

5. 컨테이너 개발 워크플로우 및 저장소 활용

5.1. Code → Build → Test → Release 워크플로우

  1. Code: 샘플 Python Flask 웹 애플리케이션 코드를 복제합니다.Bash

    git clone https://github.com/joozero/amazon-eks-flask.git
    cd amazon-eks-flask
    
  2. Build: 프로젝트 내 Dockerfile을 사용하여 이미지를 빌드합니다.DockerfileBash

    # Dockerfile 내용 요약
    FROM python:3.9-alpine
    WORKDIR /app
    COPY requirements.txt .
    RUN pip3 install -r requirements.txt
    COPY . .
    CMD ["python3", "app.py"]
    
    docker build -t my-flask-app:latest .
    
  3. Test: 빌드된 이미지를 컨테이너로 실행하고 웹 서비스가 정상 동작하는지 테스트합니다.Bash

    docker run -d -p 80:8080 --name my-app my-flask-app:latest
    
  4. Release: 완성된 이미지를 Docker Hub와 같은 컨테이너 레지스트리에 업로드합니다.

    • Docker Hub 로그인: Access Token을 발급받아 로그인합니다.Bash

      docker login docker.io -u <사용자명>
      # Password 입력란에 Access Token 붙여넣기
      
    • 이미지 태그 변경: [레지스트리]/[사용자명]/[이미지명]:[태그] 형식으로 태그를 추가합니다.Bash

      docker tag my-flask-app:latest docker.io/mupersei/my-flask-app:latest
      
    • 이미지 푸시: 태그가 지정된 이미지를 레지스트리에 업로드합니다.Bash

      docker push docker.io/mupersei/my-flask-app:latest
      

5.2. Docker 이미지 보안성 검토

  • 공식 이미지 사용: 신뢰할 수 있는 공식 이미지를 Base 이미지로 사용합니다.
  • 레이어 최소화: 다단계 빌드(multi-stage build)를 활용하여 이미지 레이어 수를 줄입니다.
  • 특정 버전 명시: latest 대신 python:3.9-alpine처럼 구체적인 버전을 명시합니다.
  • 권한 제한: USER 명령어를 사용하여 root가 아닌 일반 사용자로 컨테이너를 실행합니다.
  • 불필요한 소프트웨어 제거: 이미지에 꼭 필요한 패키지만 포함시킵니다.
  • 취약점 스캔: Trivy, Clair와 같은 도구로 이미지를 스캔하여 보안 취약점을 점검합니다.
  • ADD 대신 COPY 사용: ADD는 URL에서 파일을 가져와 압축을 해제하는 기능이 있어 보안상 위험할 수 있으므로, 단순 파일 복사에는 COPY를 사용합니다.