Cloud & Platform
Azure 계정 보안, 스토리지 및 Docker 활용 가이드
Azure 계정 보안, 스토리지 및 Docker 활용 가이드 학습 내용을 정리한 백필 노트입니다.
이 글은 2025년 학습 기록을 블로그 형식으로 정리한 백필 노트입니다.
1. Azure 계정 보안 강화
1.1. 다단계 인증(MFA) 설정
OTP(One-Time Password)를 사용하여 계정 보안을 강화합니다. OTP는 일정 시간 동안만 유효한 임시 비밀번호로, 로그인 시 추가 인증 수단으로 사용됩니다.
1.1.1. 테넌트 관리 계정에 적용
- MFA 활성화:
- Azure Portal에서
ID > 사용자 > 모든 사용자로 이동합니다. - MFA를 적용할 사용자 계정을 클릭한 후, 상단의 'MFA 사용' 버튼을 누릅니다.
- Azure Portal에서
- 사용자 설정 (최초 로그인 시):
- 활성화 후 해당 계정으로 시크릿 모드에서 새로 로그인하면 2단계 인증 설정 화면이 나타납니다.
Google Authenticator와 같은 OTP 앱을 스마트폰에 설치합니다.- 앱에서 'QR 코드 스캔'을 선택하고 화면에 표시된 QR 코드를 스캔합니다.
- 앱에 생성된 6자리 코드를 입력하여 인증을 완료합니다.
- 이후 로그인 또는 중요한 작업 수행 시 OTP 인증이 요구됩니다.
[참고] MFA 인증 해제 방법
MFA를 설정한 동일한 사용자 관리 페이지에서 해당 사용자를 선택하고 'MFA 사용 안 함' 버튼을 클릭하여 비활성화할 수 있습니다.
1.1.2. 마이크로소프트 개인 계정에 적용
- 설정 페이지 이동:
- Azure Portal 우측 상단의 프로필 아이콘을 클릭하여 **'Microsoft 계정 보기'**로 이동합니다.
보안 > 로그인 방법 관리페이지로 이동합니다.
- 2단계 인증 활성화:
- '추가 보안' 섹션에서 **'2단계 인증'**을 **'켜기'**로 설정합니다.
- 이후 과정은 테넌트 관리 계정과 동일하게
Google Authenticator앱으로 QR 코드를 스캔하여 설정합니다.
[참고] 2단계 인증 해제 방법
동일한 '추가 보안' 섹션에서 **'2단계 인증'**을 **'비활성화'**하여 해제할 수 있습니다.
1.2. 비밀번호 정책 설정 (프리미엄 계정)
Microsoft Entra ID에서 조직의 비밀번호 정책을 설정하여 보안을 강화할 수 있습니다. (무료 계정에서는 제한됨)
- Entra 관리 센터 이동: Azure Portal에서
Microsoft Entra ID를 검색하고 'Go to Microsoft Entra' 링크를 클릭합니다. - 암호 보호 설정:
보호 > 인증 방법 > 암호 보호로 이동합니다.- 여기서 계정 잠금 임계값(로그인 실패 허용 횟수), 사용자 지정 금지 암호 목록 등을 설정할 수 있습니다.
- 알림 설정:
보호 > 암호 재설정 > 알림메뉴에서 암호 재설정 시 사용자나 관리자에게 알림을 보내도록 구성할 수 있습니다.
2. Azure 사용자 및 그룹 관리 (RBAC)
사용자를 그룹으로 묶고, 그룹에 역할을 할당하여 리소스 접근 권한을 효율적으로 관리(RBAC: Role-Based Access Control)합니다.
2.1. 사용자 및 그룹 생성
- 새 사용자 만들기:
- Microsoft Entra 관리 센터에서
ID > 사용자 > 모든 사용자 > 새 사용자 만들기를 선택합니다. - 사용자 계정 이름:
test-user - 암호:
Optional12!@(자동 생성 해제)
- Microsoft Entra 관리 센터에서
- 새 그룹 만들기:
- Azure Portal에서
Groups로 이동하여 'New Group'을 클릭합니다. - Group type:
Security(리소스 접근 권한 관리용) - Group name:
test-group
- Azure Portal에서
- 그룹에 멤버 추가:
- 생성된
test-group으로 이동하여Manage > Members > Add members를 선택합니다. test-user를 검색하여 그룹에 추가합니다.
- 생성된
💡 불필요한 계정 정리
사용하지 않는 계정은 보안 위협이 될 수 있으므로 반드시 삭제하거나 비활성화해야 합니다. 이는 Azure 보안 모범 사례에서 강조하는 중요한 항목입니다.
2.2. 그룹에 권한 부여 및 확인
- 테스트용 리소스 그룹 생성:
- Azure Portal에서 '리소스 그룹'으로 이동하여
test-rg라는 이름의 리소스 그룹을 생성합니다.
- Azure Portal에서 '리소스 그룹'으로 이동하여
- 역할 할당:
- 생성된
test-rg리소스 그룹의액세스 제어(IAM) > 추가 > 역할 할당 추가로 이동합니다. - 역할:
기여자(Contributor)선택 (리소스 생성/수정/삭제 가능, 권한 할당 불가) - 구성원:
test-group을 선택하여 역할을 할당합니다.
- 생성된
- 권한 확인:
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 컨테이너 사용 (객체 스토리지)
- 컨테이너 생성:
storagecloud001계정 내데이터 스토리지 > 컨테이너에서blob이라는 이름의 컨테이너를 생성합니다. - 파일 업로드: 생성된
blob컨테이너에 파일을 업로드합니다. - 외부 공개 설정:
설정 > 구성에서 **'Blob 익명 액세스 허용'**을 **'사용'**으로 변경합니다.blob컨테이너의 '액세스 수준 변경'에서 **'Container(컨테이너, Blob에 대한 익명 읽기 액세스)'**를 선택합니다.- 이제 각 파일의 URL을 통해 외부에서 직접 파일에 접근할 수 있습니다.
- 주의:
?comp=list파라미터를 URL에 추가하면 컨테이너 내 모든 파일 목록이 노출될 수 있으므로, 보안을 위해 CDN 등을 앞에 두는 것이 좋습니다.
3.3. 파일 공유(File Share) 생성 및 연결 (NAS)
여러 VM에서 공유하여 사용할 수 있는 네트워크 드라이브를 구성합니다.
- File Share 생성:
storagecloud001계정 내파일 공유에서share라는 이름의 파일 공유를 생성합니다. - 테스트용 VM 생성:
sa-rg리소스 그룹에linuxVM(SSH 허용)과windowVM(RDP 허용)을 각각 생성합니다. (사용자 이름:azureuser) - Windows VM에 연결 (Z: 드라이브):
share파일 공유의 '연결' 메뉴에서 Windows용 연결 스크립트를 복사합니다.windowVM에 RDP로 접속하여 PowerShell(관리자)을 열고 복사한 스크립트를 실행합니다.- 탐색기에서 Z: 드라이브가 마운트된 것을 확인할 수 있습니다.
- Linux VM에 연결 (/media/share):
- '연결' 메뉴에서 Linux용 연결 스크립트를 복사합니다.
linuxVM에 SSH로 접속하여 복사한 스크립트를 실행합니다./media/share디렉터리가 마운트되며,ls -al /media/share명령어로 Windows VM에서 업로드한 파일이 보이는지 확인합니다.
3.4. 테이블(Table) 생성 및 사용 (NoSQL)
- 테이블 생성:
storagecloud001계정 내테이블에서table이라는 이름의 테이블을 생성합니다. - System ID(Managed Identity) 설정:
linuxVM 설정에서ID > 시스템 할당을 **'켬'**으로 설정하여 VM에 고유 ID를 부여합니다.
- 권한 부여:
storagecloud001계정의액세스 제어(IAM)에서 역할 할당을 추가합니다.- 역할:
저장소 테이블 데이터 기여자 - 구성원:
linuxVM의 시스템 할당 ID를 선택합니다.
- Python 스크립트로 데이터 조작:
-
linuxVM에 접속하여 필요한 Python 라이브러리를 설치합니다.Bashsudo 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 등의 부가 기능을 활용합니다.
- Blob Storage 준비: 정적 웹사이트용 스토리지 계정(
static-website-username) 및 컨테이너(html)를 생성하고index.html을 업로드합니다. - Private Link 구성: 스토리지 계정의 '네트워킹' 설정에서 **'공용 액세스'를 '사용 안 함'**으로 변경하고, 프라이빗 엔드포인트를 생성하여 내부 네트워크를 구성합니다.
- Front Door (Premium) 구성:
- Front Door 생성 시 원본(Origin)으로 Blob Storage를 선택하고 '프라이빗 링크'를 활성화합니다.
- Front Door가 프라이빗 엔드포인트 생성을 자동으로 요청하고 승인 대기 상태가 됩니다.
- 스토리지 계정의 프라이빗 엔드포인트 연결 설정에서 해당 요청을 승인합니다.
- 결과: 이제 스토리지 계정은 외부에서 직접 접근할 수 없으며, 오직 Front Door에서 제공하는 도메인을 통해서만 안전하게 콘텐츠에 접근할 수 있습니다.
3.7. 스토리지 리소스 정리
리소스 그룹 삭제 시 **잠금(Lock)**이나 Recovery Services 자격 증명 모음(Vault) 때문에 실패할 수 있습니다.
- 잠금 해제: 삭제하려는 리소스에 잠금이 설정되어 있다면 해당 리소스의 '잠금' 메뉴에서 먼저 해제합니다.
- 자격 증명 모음 삭제: Vault는 별도로 삭제해야 합니다. Vault 삭제 메뉴에서 제공하는 PowerShell 스크립트를 다운로드하여 Cloud Shell에서 실행하면 관련 종속성과 함께 깨끗하게 삭제됩니다.
- 리소스 그룹 삭제: 위 두 가지 조치 후 리소스 그룹을 다시 삭제하면 정상적으로 정리됩니다.
4. Azure VM에서 Docker 사용하기
4.1. Docker 환경 구성
-
VM 생성:
docker리소스 그룹에docker라는 이름의 Ubuntu VM을 생성합니다. (인바운드 포트: 80, 443, 22) -
Docker 설치: VM에 SSH로 접속하여 아래 명령어를 실행합니다.Bash
sudo su sudo apt update && sudo apt install docker.io -y -
설치 확인:
docker info명령어로 Docker 엔진 정보를 확인합니다.
4.2. Docker 기본 사용법
-
이미지 검색 및 다운로드:
- Docker Hub에서
nginx이미지를 검색합니다. docker pull nginx:1.28.0-alpine-slim명령어로 특정 버전의 이미지를 다운로드합니다.docker images로 다운로드된 이미지 목록을 확인합니다.
- Docker Hub에서
-
컨테이너 생성 및 실행:
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-slimd: 백그라운드 실행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 컨테이너 배포
-
이미지 다운로드:
docker pull jenkins/jenkins:lts-jdk17 -
컨테이너 실행:
docker inspect로 노출된 포트(8080)를 확인하고 실행합니다.Bashdocker run -d -p 80:8080 --name jk jenkins/jenkins:lts-jdk17 -
초기 비밀번호 확인: Jenkins 웹 페이지에 접속하면 초기 비밀번호 경로가 안내됩니다. 아래 두 방법 중 하나로 비밀번호를 확인하여 로그인합니다.Bash
# 방법 1: 로그 확인 docker logs jk # 방법 2: 파일 내용 확인 docker exec jk cat /var/jenkins_home/secrets/initialAdminPassword
5. 컨테이너 개발 워크플로우 및 저장소 활용
5.1. Code → Build → Test → Release 워크플로우
-
Code: 샘플 Python Flask 웹 애플리케이션 코드를 복제합니다.Bash
git clone https://github.com/joozero/amazon-eks-flask.git cd amazon-eks-flask -
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 . -
Test: 빌드된 이미지를 컨테이너로 실행하고 웹 서비스가 정상 동작하는지 테스트합니다.Bash
docker run -d -p 80:8080 --name my-app my-flask-app:latest -
Release: 완성된 이미지를 Docker Hub와 같은 컨테이너 레지스트리에 업로드합니다.
-
Docker Hub 로그인: Access Token을 발급받아 로그인합니다.Bash
docker login docker.io -u <사용자명> # Password 입력란에 Access Token 붙여넣기 -
이미지 태그 변경:
[레지스트리]/[사용자명]/[이미지명]:[태그]형식으로 태그를 추가합니다.Bashdocker 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를 사용합니다.