사용자 계정
고친 사람 github-actions[bot]
사용자 계정은 시스템이 요청을 낸 쪽이 누구인지 알아보게 해 줍니다. 로그인한 뒤의 요청은 전부 그 계정이 낸 것으로 봅니다. 그리고 계정에 허락된 만큼만 일을 해 줍니다. 계정은 시스템마다 따로 둡니다.
쉽고 빠른 이해
사용자 계정은 시스템이 「누가 이 일을 하려 하나」를 알아보는 단위입니다. 서버에 deploy 계정으로 들어가면 그 뒤에 친 명령은 전부 deploy 가 한 일이 됩니다.
여러 사람이 한 시스템을 같이 쓰면 누가 무엇을 해도 되는지 갈라야 합니다. 계정이 없으면 누구나 무엇이든 할 수 있습니다. 일이 터져도 누가 했는지 알 수 없습니다.
어떻게 도는가:
- 관리자나 가입 절차가 계정을 만들고 이름과 번호를 붙입니다
- 들어올 때 비밀번호 같은 수단으로 그 계정의 주인이 맞는지 확인합니다
- 그 뒤로는 요청마다 이 계정이 그 일을 해도 되는지 봅니다
대가는 관리할 거리가 늘어난다는 것입니다. 안 쓰는 계정이 남아 있으면 아무도 안 지키는 문이 하나 열려 있는 셈입니다.
상세
회사에 들어가면 사원증을 받습니다. 사원증에는 이름과 사번이 적혀 있습니다. 출입문은 사원증을 읽고 이 사람에게 문을 열어 줄지 정합니다. 회사를 떠날 때는 사원증을 돌려줍니다.
사용자 계정(user account)은 시스템이 사용자 한 명을 알아보려고 만들어 두는 기록입니다. 이 기록에는 이름과 식별 번호가 있습니다. 들어올 때 무엇으로 확인할지와 무엇을 해도 되는지도 이 기록에 붙습니다. 리눅스 서버에 deploy 라는 계정을 만들었다고 합시다. 서버는 이 이름으로 들어온 사람이 무엇을 읽고 고칠 수 있는지를 이 기록으로 가립니다.
계정이 필요한 까닭은 한 시스템을 여럿이 같이 쓰기 때문입니다. 계정이 없으면 시스템은 요청을 낸 쪽을 가릴 수 없습니다. 그러면 누구에게나 모든 일을 허락하거나 모두를 막는 수밖에 없습니다. 일이 터져도 누가 했는지 알 수 없습니다.
이 절은 먼저 계정이 사람과 어떻게 다른지 봅니다. 그다음 계정이 인증과 인가 사이에서 무슨 일을 하는지, 계정을 두면 무엇을 치르는지 봅니다. 끝으로 계정을 두는 세 곳인 운영체제, 데이터베이스, 애플리케이션의 계정을 차례로 봅니다.
계정과 사람
계정은 사람이 아닙니다. 한 사람이 계정을 여럿 가질 수 있습니다. 개발자 한 명이 회사 서버 계정과 데이터베이스 계정과 사내 도구 계정을 따로 갖는 것이 흔한 모습입니다.
사람이 쓰지 않는 계정도 있습니다. 웹 서버나 밤마다 도는 배치 작업 같은 프로그램만 쓰는 계정을 서비스 계정이라고 부릅니다. 프로그램마다 전용 계정을 주는 이유는 피해를 가두기 위해서입니다. 그 프로그램이 뚫려도 공격자는 그 계정이 닿는 곳까지만 갈 수 있습니다.
이렇게 일마다 꼭 필요한 만큼만 권한을 주는 방식을 최소 권한 원칙이라고 부릅니다. 계정을 잘게 나눌수록 이 원칙을 지키기 쉬워집니다.
인증과 인가 사이의 계정
계정은 두 가지 확인을 잇는 고리입니다. 하나는 요청을 낸 쪽이 정말 그 계정의 주인인지 확인하는 인증입니다. 로그인 때 하는 확인이 바로 인증입니다. 비밀번호를 대조하는 것이 가장 흔한 방법입니다.
다른 하나는 인가입니다. 인증을 통과한 계정이 지금 하려는 일을 해도 되는지 확인하는 일입니다. 요청마다 하는 권한 확인이 인가입니다. 이때 보는 것이 그 계정에 붙은 권한입니다.
권한은 계정에 직접 붙기도 합니다. 계정이 많아지면 하나씩 붙이기 번거로워서 묶음을 씁니다. 묶는 방향에 따라 둘로 나뉩니다.
그룹은 계정 여럿을 묶은 것입니다. 개발팀 계정을 한 그룹에 넣고 그룹에 권한을 주면 팀원 모두가 그 권한을 받습니다.
롤은 거꾸로 권한 여러 개를 묶어 이름을 붙인 것입니다. 계정에 롤 하나를 주면 그 안의 권한을 한꺼번에 받습니다.
아래 그림이 요청 한 번이 계정을 거치는 순서입니다. 인증에서 걸리든 인가에서 걸리든 요청은 거절됩니다.
flowchart TD
A["요청이 들어온다"] --> B{"인증 · 이 계정의 주인이 맞나"}
B -->|아니다| X["거절"]
B -->|맞다| C{"인가 · 이 계정이 이 일을 해도 되나"}
C -->|안 된다| X
C -->|된다| D["일을 한다 · 계정 이름을 로그에 남긴다"]
마지막 칸의 기록도 계정이 하는 일입니다. 시스템은 누가 무엇을 했는지를 계정 이름으로 로그에 적습니다. 나중에 사고를 되짚을 때 이 기록이 단서가 됩니다. 이런 용도로 남기는 로그를 감사 로그라고 부릅니다.
계정을 두는 대가
계정은 만든 뒤에도 돌봐야 합니다. 퇴사한 사람이나 내린 프로그램의 계정이 남아 있으면, 그 비밀번호를 아는 누군가가 여전히 들어올 수 있습니다. 아무도 안 지키는 문이 하나 열려 있는 셈입니다.
그래서 안 쓰는 계정을 막아 두는 계정 잠금이나 삭제가 따로 챙겨야 할 운영 작업이 됩니다. 계정이 많아질수록 이 일도 늘어납니다.
운영체제의 계정
리눅스 같은 유닉스 계열 운영체제는 계정마다 이름과 UID(User Identifier, 사용자 식별 번호)를 둡니다. 운영체제의 핵심인 커널은 이름이 아니라 이 번호로 계정을 가립니다. 이름은 사람이 읽기 편하라고 붙여 둔 것입니다.
파일은 자기 주인의 UID 를 기록해 둡니다. 파일에는 파일 권한도 붙어 있습니다. 누구에게 읽기·쓰기·실행을 허락하는지 적어 둔 값입니다.
실행 중인 프로그램인 프로세스도 자기를 띄운 계정의 UID 를 지니고 돕니다. 프로세스가 파일을 열려고 하면 커널은 두 UID 를 견주고 파일 권한을 봅니다. 그리고 열어 줄지 정합니다.
UID 가 0 인 계정은 root입니다. root 는 이 권한 확인을 건너뜁니다. root 로 잘못 친 명령이나 root 를 손에 넣은 공격자를 권한 확인이 멈춰 주지 못한다는 뜻입니다.
그래서 평소 작업은 root 가 아닌 계정으로 합니다. root 가 필요한 명령만 sudo 로 실행합니다. sudo 는 명령 하나를 root 권한으로 돌려 주는 프로그램입니다.
계정 목록은 /etc/passwd 파일에 한 줄에 한 계정씩 적힙니다. 한 줄에는 이름과 UID 말고도 홈 디렉토리와 로그인 셸이 들어갑니다. 홈 디렉토리는 그 계정 몫의 개인 폴더입니다. 셸은 로그인하면 처음 뜨는 명령 입력 프로그램입니다.
비밀번호는 이 파일에 두지 않습니다. root 만 읽을 수 있는 /etc/shadow 파일에 둡니다. 그것도 원문이 아니라 해시로 둡니다. 해시는 원래 값으로 되돌릴 수 없게 바꾼 값입니다.
서버가 여러 대면 대마다 같은 계정을 똑같이 만들어 둬야 합니다. 손으로 하면 서버마다 조금씩 어긋나기 쉽습니다. 설정 관리 도구가 계정을 패키지나 설정 파일과 함께 서버마다 같은 상태로 맞춰 둡니다.
데이터베이스의 계정
데이터베이스 서버도 접속하는 쪽을 계정으로 가립니다. 이 계정은 운영체제 계정과 따로 삽니다. 이름이 같아도 서로 다른 기록입니다.
애플리케이션 서버는 대개 데이터베이스 계정 하나로 접속합니다. 서비스에 가입한 사람이 백만 명이어도 데이터베이스가 보는 계정은 애플리케이션 서버의 계정 하나입니다. 그래서 이 계정에는 애플리케이션이 쓰는 테이블을 읽고 쓰는 권한만 주는 것이 보통입니다.
권한은 GRANT 명령으로 줍니다. 어느 계정이 어느 테이블을 읽고 쓸 수 있는지를 테이블 단위까지 잘게 정할 수 있습니다.
GRANT 로 가리키는 테이블은 스키마라는 이름 공간 안에 들어 있습니다. 스키마는 테이블 여럿을 한 이름 아래 모아 둡니다. 그래서 이름이 같은 테이블도 스키마가 다르면 함께 있을 수 있습니다.
애플리케이션의 계정
웹 서비스에 가입하면 생기는 것도 사용자 계정입니다. 이 계정은 운영체제나 데이터베이스가 아니라 서비스가 직접 만든 기록입니다. 대개 데이터베이스 테이블의 한 행이 계정 하나입니다.
아래는 이런 계정을 담는 테이블의 가장 작은 꼴입니다. 줄마다 오른쪽에 그 칸이 맡는 일을 적었습니다.
CREATE TABLE users (
id BIGINT PRIMARY KEY, -- 계정 번호
email TEXT UNIQUE, -- 로그인 이름
pw TEXT -- 비밀번호 해시
);
id 칸은 기본 키입니다. 행마다 하나뿐인 값이라 계정을 가리키는 번호로 씁니다. email 칸에는 유니크 제약을 걸어 같은 이메일로 계정이 둘 생기지 않게 합니다.
pw 칸에는 비밀번호 원문 대신 해시를 넣습니다. 앞에서 본 대로 되돌릴 수 없게 바꾼 값입니다. 로그인 때는 들어온 비밀번호를 같은 방식으로 바꿔 이 값과 견줍니다. 테이블이 새어 나가도 원문 비밀번호는 바로 드러나지 않습니다.
게시글이나 주문 같은 다른 테이블은 이 id 를 외래 키로 가리킵니다. 그래서 어느 글이 누구 것인지가 정해집니다.
계정 행을 함부로 지우면 이 글들이 주인 없는 행이 됩니다. 그래서 탈퇴한 계정은 지우는 대신 탈퇴 표시만 남기기도 합니다. 이 방식을 소프트 삭제라고 부릅니다.
애플리케이션의 계정은 데이터입니다. 데이터베이스를 잃으면 계정도 같이 잃습니다.
GitLab 데이터 삭제 사고는 GitLab.com 의 운영 데이터베이스가 실수로 지워진 사고입니다. 이때 사라진 데이터에 사용자 계정도 들어 있었습니다. 계정이 데이터베이스의 행이었기 때문입니다.
세 곳의 계정 비교
세 곳의 계정은 뜻이 같습니다. 모두 요청을 낸 쪽을 알아보고 권한을 매다는 기록입니다. 다른 것은 그 기록이 어디에 살고 무엇을 지키느냐입니다.
| 운영체제 | 데이터베이스 | 애플리케이션 | |
|---|---|---|---|
| 기록이 사는 곳 | 운영체제의 계정 파일 | 데이터베이스 서버 안 | 서비스가 만든 테이블 |
| 계정을 가리키는 값 | UID | 계정 이름 | 기본 키 |
| 지키는 것 | 파일과 프로세스 | 테이블과 스키마 | 글·주문 같은 서비스 데이터 |
| 주로 쓰는 쪽 | 서버에 들어가는 사람과 프로그램 | 애플리케이션 서버 | 서비스 이용자 |
관련 항목
계정의 주인임을 확인하는 수단
인증 · 비밀번호 · 다중 인증 · 패스키 · 세션 · 싱글 사인온 · 신원 제공자
계정에 권한을 매다는 방식
인가 · 권한 · 그룹 · 롤 · 역할 기반 접근 제어 · 접근 제어 목록 · 최소 권한 원칙 · 권한 상승
운영체제 계정을 이루는 구성 요소
UID · 홈 디렉토리 · 셸 · 파일 권한 · 프로세스 · 커널
사용자 계정의 하위 종류
서비스 계정 · root · 슈퍼유저 · 게스트 계정
애플리케이션 계정을 테이블에 담을 때 쓰는 개념
기본 키 · 외래 키 · 유니크 제약 · 해시 · 소프트 삭제
데이터베이스 계정이 다루는 객체
계정을 만들고 지키는 운영 작업
설정 관리 · 감사 로그 · 로그 · 계정 잠금 · 비밀번호 재설정
계정을 노리거나 잃는 사고
계정 탈취 · 크리덴셜 스터핑 · 무차별 대입 공격 · GitLab 데이터 삭제 사고
이름이 겹치는 헷갈리는 이웃
다른 이름: user account · 유저 계정 · 계정