TIL(Today I Learned) (62)

반응형

 

 

 

 

🍉 GitHub 레포지토리에 꼭 필요한 파일

 

 

🥝 README.md

포함할 정보들

  • 프로젝트 이름
  • 팀원 소개
  • 핵심 기능 소개

 

 

🥝 .gitignore

git으로 관리하지 않는 파일 모음

개인이 관리해야하는 secret token, 공유할 필요없는 설정 파일 등을 추가

 

 

🥝 LICENSE

라이센스 표기

오픈소스 소프트웨어 개발은 보통 제약이 적은 MIT 라이센스나 Apache License 적용

다양한 라이센스가 있어서 필요한 걸로 적용

 

 

 

🍉 프로젝트 관리에 활용할 수 있는 GitHub 기능들

 

1. Issue

새로운 기능을 제안하거나 버그를 제보하는 등 프로젝트 이슈를 올리는 곳

Pre-Project에서 하나의 칸반 티켓으로 사용하면 된다.

 

 

2. Milestone

이정표 역할

task 카드(Issue)를 그룹화하는데 사용

연결된 태스크 카드가 종료되면 Milestone마다 진행 상황이 업데이트

 

 

3. Pull Request

작업한 내용을 branch에 합칠 수 있는지 확인하는 요청

커밋한 코드를 따로 선택하여 해당 부분에 코멘트(코드 리뷰)를 달 수 있음

머지의 규칙을 정할 수도 있음

 

 

4. Project

업무 관리를 해줄 수 있게 돕는 새로운 기능

칸반 보드를 생성하고 칸반으로 Pre-Project의 업무 흐름을 관리

 

 

칸반 보드란?

업무를 효율적으로 관리하기 위한 시각적 프로젝트 관리의 한 형태

칸반이란? 팀이 수행해야 하는 업무와 각 팀원이 맡을 수 있는 작업량 간에 균형을 맞추는 수단

칸(看, Kan, 신호), 반(板, Ban, 판)

칸반보드에서 업무를 열로 구성된 프로젝트 보드에 표시한다.

각 열은 업무 단계를 나타냄

기본적인 틀 : 할 일, 진행 중, 완료

개별작업은 보드에서 비주얼 카드로 표시

 

출처 : asana

 

 

 

✅ Work In Progress(WIP)로 흐름 관리

 

진행 중인 업무의 개수를 제한하여 과도하게 업무가 쌓이지 않아 원활한 업무 흐름을 만들어 낼 수 있다.

팀원이 100%의 리소스를 사용하는 상태에서 새로운 업무가 쌓이게 되면 업무 과부하로 효율이 안나올 수 있다.

단기간에 많은 아웃풋을 내려고 하면 금방 지쳐서 번아웃이 올 수 있으므로 적당하게 분배하자.

업무 개수를 적절하게 정해서 맥락 전환(context switching) 없이 현재 하고 있는 프로세스에 집중할 수 있게 하여 업무 효율이 증가한다.

 

 

 

✅ 명확한 팀 정책 설정

 

칸반을 잘 활용하기 위해서는 정책을 설정해야 한다.

언제든 팀원이 모여서 다시 조정 가능하다.

 

 

✅ 회의와 리뷰를 통한 업무 개선

 

데일리 칸반 회의

주간 보충 회의

월간 또는 주간으로 KPT 회고를 진행하는 것도 좋음

 

 

 

🍉 GitHub Milestone

 

GitHub 마일스톤 튜토리얼

 

여러가지 이슈들을 그룹화해서 진척도를 한눈에 볼 수 있다.

 

예) Bare Minimum Requirement, Advanced Challenge

 

 

 

🍉 변경사항 PR 하기

 

🥝 Pull Request 시 체크하면 좋은 것들

  • title이 올바른 이슈 타입인가
  • 특정 이슈를 해결할 때, PR의 제목에 issue 넘버가 적혀있는가 (ex. fix #12)
  • 커밋 제목이 가이드라인을 따랐는가
  • 변경사항의 테스트가 추가되었는가
  • 문서들이 추가되거나 업데이트 되었는가
  • breaking change를 소개하지 않거나 breaking change에 대한 설명이 있다. (? 무슨말인지 잘 이해가 안간다)

👆🏻 출처 nhn tuieditor

위와 같은 자료들을 참고해서 Pull Request 에 대한 가이드라인이나 체크리스트를 작성해두는 것이 좋다.

 

 

새로운 branch 를 만들어서(feat: xxx) main  브랜치의 변경없이 새로운 기능을 구현한 후 마치면 main(또는 dev) 브랜치에 합친다.

merge 된 branch는 기본적으로 삭제하지만 나중에 다시 볼 일이 있다면 삭제하지 않아도 된다.

 

 

🥝 브랜치 생성하기 (create 옵션 -c)

 

git switch -c feature/sign-up
git checkout -c feature/sign-up

 

 

🥝 기존 브랜치로 옮기기

 

git switch main
git checkout main

 

 

🥝 main 브랜치에 병합하기

 

git merge feature/sign-up

 

 

🥝 merge된 브랜치 삭제하기(delete 옵션 -d)

 

git branch -d feature/sign-up

➡️ branch가 합쳐지지 않으면 삭제하지 못하도록 설정되어 있음.

merge 하지 않고 삭제하고 싶으면 -D 옵션을 사용하면 됨

 

 

 

🍉 Git 헷갈리는 명령어

 

git reset [file]

-> 추가한 파일을 언스테이징, 변경사항은 유지됨

 

git diff

-> 스테이지되지 않은 변경 사항을 보여줌

 

git diff --staged

-> 스테이지했지만 커밋하지 않은 변경사항을 보여줌

 

git branch

-> 현재 브랜치 목록을 보여줌(*표시가 현재 작업중인 브랜치)

 

git branch [branch-name]

-> 현재 커밋에서 새로운 브랜치를 생성한다.

 

git branch -c [branch-name]
git checkout -b [branch-name]

-> 새로운 브랜치를 생성하고 작업을 해당 브랜치로 전환한다.

 

git merge [branch-name]

-> 현재 브랜치에 특정 브랜치를 병합한다.

 

git log

-> 현재 브랜치의 모든 커밋 히스토리를 보여줌

 

git log B..A

-> 브랜치B에 없는 브랜치A의 모든 커밋 히스토리를 보여줌

 

git log --follow [file]

-> 해당 파일의 변경 사항이 담긴 모든 커밋을 표시(파일 이름 변경도 표시)

 

git diff B...A

-> 브랜치A에는 있지만 브랜치B에 없는 것의 변경내용(diff)을 표시한다.

 

git remote add [alias] [url]

-> url을 통해 특정 원격 저장소를 별칭으로 추가한다.

 

git fetch [alias]

-> 별칭으로 추가한 원격 저장소에 있는 모든 브랜치 및 데이터를 로컬로 가져옴

 

git merge [alias]/[branch]

-> 리모트 브랜치를 현재 작업중인 브랜치와 병합하여 최신상태로 만듬

 

git push [alias] [branch]

-> 로컬 브랜치의 커밋을 리모트 브랜치에 전송함

 

git pull

-> 원격 저장소의 정보를 가져와 자동으로 로컬 브랜치에 병합 (pull = fetch + merge 이라서 pull을 주로 사용)

 

git rebase [branch]

-> 특정 브랜치의 분기 이후 커밋을 현재 작업중인 브랜치에 병합 (merge와 비슷하지만 다르다.)

 

git reset --hard [commitish]

-> 특정 커밋 전으로 돌아가며 스테이지된 변경 사항을 모두 지움

 

git stash

-> 수정하거나 스테이지 된 변경사항을 스택에 임시 저장하고 현재 작업 내역에서 지움

 

git stash list

-> 스택에 임시 저장된 변경사항의 목록을 보여줌

 

git stash apply

-> 스택에 임시 저장된 변경사항을 현재 작업 내역에 적용함

 

git stash pop

-> 스택에 임시 저장된 변경사항을 현재 작업 내역에 적용하고 스택에서 삭제함

 

git stash drop

-> 스택에 임시 저장된 변경사항을 삭제함

 

 

🍉 Git flow

 

유명하고 많이 쓰이는 branch 전략이다.

 

🥝 Coz’s Git flow

-> Git flow를 단순화

 

🥝 Coz’s Git flow 브랜치 전략

 

  • main : 사용자에게 언제든 배포할 수 있는 브랜치
  • dev : 다음 버전 배포를 위한 "개발 중" 브랜치
  • feat/작업이름 : 기능 개발, 리팩토링, 문서 작성등을 위한 브랜치

 

branch에 대한 최소한의 기준을 팀원과 상의할 필요가 있음!

 

어떤 때 dev -> main 으로 merge 할지?

예시) 대표적 기능 완성, 기획한 레이아웃과 전체적 디자인 얼추 완성, 클라이언트-서버-데이터베이스가 공개된 웹에서 정상적으로 통신, 최소한 보안 마련

 

 

⭐️ 실제 프로젝트 때는 브랜치를 로컬에서 합치기 보다 pull request 해서 같이 코드 리뷰를 충분히 하거나 확인을 하고 머지하는 것이 바람직하다. (로컬에서 머지 ❌, 브랜치 PR 요청 ✅)

 

✔️ branch는 기능별로 만들고 기능별로 담당자를 선정한다.

 

 

개발환경 구성(Back-End)

1. 통합 개발 환경 선택 (IDE)

IntelliJ

 

2. JDK 선택

AdoptOpenJDK가 많이 사용됨 (표준은 아님)

버전 11 지정

 

3. Framework 선택

Spring-boot 사용

버전은? 2.7.1 버전으로 지정

 

4. build 방식 선택

Gradle 방식 사용

-> XML 방식으로 작성하는 Maven보다는 Groovy 방식으로 작성하는 Gradle이 작성 및 문제 해결 시 용이

 

5. 형상관리(Software Configuration Management) 방법 결정

버전관리 및 개발 협업을 위한 형상관리

GIthub

반응형
반응형

 

 

 

 

 

 

🍙 Spring Security의 인증 처리 흐름

 

 

Authentication flow

 

 


 

 

🍙 Authentication(인증)

 

 

🍘 Authentication 인터페이스

 

🍥 Spring Security에서 Authentication은 인터페이스로 존재한다.

🍥 사용자가 인증을 성공적으로 수행하면 사용자의 인증정보를 가지고 있는다.

🍥 SecurityContextHolder는 SecurityContext를 호출하고 SecurityContext는 Authentication 객체를 갖고 있다.

🍥 일반적으로 많이 사용하는 구현체는 UsernamePasswordAuthenticationToken 이다.

➡️ 사용자의 고유 식별자(Username)과 암호(Password)로 간단하게 Authentication 객체를 생성할 수 있다.

 

 

🍘 Spring Security내에서의 Authentication 주요 목적

 

  • 사용자가 인증을 위해 제공한 Credential(자격증명)을 제공하기 위해 AuthenticationManager에 대한 입력값이다.
  • 현재 인증된 사용자를 나타낸다. 현재 Authenticaion은 SecurityContext에서 얻을 수 있다.

 

 

 

🍘 Authentication 에 포함된 정보

 

🍰 principal

  • 사용자를 식별한다.
  • UserDetails 인터페이스 구현체는 사용자의 username과 password로 인증이 이루어진다.
  • 구현체 위치 : org.springframework.security.core.userdetails.User
  • 직접 UserDetails를 상속받아 구현할 수도 있다.

 

🍰 credentials

  • 대부분 password 이다.
  • 대부분의 경우 사용자 안증 후에 유출되지 않도록 삭제된다.

 

🍰 authorities

  • AuthenticationManager에 의해 부여된 인가에 대한 정보이다.
  • 부여된 권한에 대한 정보는 GrantedAuthority로 추상화한다.
  • 일반적으로 사용하는 구현체는 SimpleGrantedAuthority 이다.

 

 

 

🍘 Spring Security 에서 Authentication

 

  • Spring Security 는 종합적인 인증처리를 지원한다.
  • 인증은 특정 리소스에 접근하려고 하는 사용자가 누구인지 확인할 때 사용한다.
  • 보통 사용자가 이름과 비밀번호를 입력하는 것으로 사용자를 인증한다.
  • 한번 인증하면 사용자를 식별하고 권한을 부여할 수 있다. (Authorization, 인가)

 

 

 

🍘 Password Storage

 

Spring Security의 PasswordEncoder 인터페이스는 비밀번호를 안전하게 저장할 수 있도록 단방향 변환을 수행해준다.

  • PasswordEncoder 는 비밀번호를 단반향(비밀번호 -> 암호화)으로 변환, 양방향 변환 목적 x
  • 인증에 사용할 credential 정보를 저장한다.

PasswordEncoder 를 사용해서 저장하는 비밀번호는 인증 시점에 사용자가 입력하는 비밀번호와 비교하는 용도이다.

 

 

 

🍘 Password Storage History

 

패스워드를 저장하는 표준 매커니즘의 변화

 

🍰 처음에는 일반 텍스트로 암호를 저장했다.

  • 비밀번호를 담고 있는 DB에 접근하려면 credential이 필요했기 때문에 비밀번호가 안전하다고 생각했다.
  • 악의적인 SQL Injection 같은 공격으로 “Data dump”를 읽어갈 수 있는 방법이 존재한다.

 

🍰 암호를 저장하기 전에 SHA-256 같은 단방향 해시를 실행한 후 암호를 저장했다.

  • 사용자가 인증을 시도할 때 입력한 암호를 해시 처리하여 저장된 비밀번호와 입력한 비밀번호의 해시값을 비교한다.
  • 시스템에선 비밀번호의 단방향 해시만 저장하면 됐다.
  • 악의적인 공격으로 정보가 유출이 되더라도 실제 비밀번호가 아닌 비밀번호의 단방향 해시값만 알 수 있다.
  • 단방향 해시값만으로 비밀번호를 추측하기는 불가능에 가까웠다.
  • 하지만 레인보우 테이블로 알려진 룩업 테이블이 만들어지면서 안전하지 않게 됐다.

 

🍰 레인보우 테이블을 무력화하기 위해 솔티드 패스워드(salted password)를 사용했다.

  • 비밀번호 해시 함수 ➡️ 모든 사용자의 비밀번호로 랜덤 바이트(솔트)를 만들었다.
  • 솔트와 사용자의 비밀번호로 해시 함수를 실행하면 유니크한 해시값을 생성한다.
  • 솔트는 유니크하기 때문에 솔트와 비밀번호 조합은 레인보우 테이블을 무력화할 수 있었다.
  • 하지만 기술이 발전함에 따라 최신 하드웨어를 사용하면 초당 수십억 건을 계산할 수 있게 되며 비밀번호를 쉽게 해독할 수 있어 SHA-256같은 해시가 더 이상 안전하지 않게 되었다.

 

🍰 현재는 적응형 단방향 함수(adaptive one-way function)로 비밀번호를 저장하는 것을 권장한다.

  • CPU, 메모리 등 많은 리소스를 소모해서 비밀번호를 검증 ➡️ 애플리케이션 성능이 크게 떨어질 수 있다.
  • 적응형 단방향 함수는 하드웨어 사양에 따라 work factor를 구성할 수 있다.
  • 워크 팩터(work factor) : 공격자가 암호를 깨는데 드는 노력, 시스템에서 비밀번호를 검증할 때 소요되는 시간과 관련있다.
  • 공격자가 쉽게 비밀번호를 해독하지 못하게 만들지만 시스템 자체에 부담이 된다.
  • Spring Security 는 work factor 시작점을 제공하지만 성능에 따라 각자의 시스템에 맞게 설정하는게 좋다.
  • 종류 : bcrypt, PBKDF2, scrypt, argon2
  • 사용하는 부분에서 장기 자격 증명(사용자 이름및 암호)에서 단기 자격 증명(세션, OAuth 토큰 등)으로 바꾸는게 좋다. ➡️ 단기 자격 증명은 동일한 보안 수준을 유지하면서도 빠르게 검증할 수 있다.

 

 


 

 

🍙 Servlet Authentication Architecture

 

 

🍘 Architecture

 

Servlet authentication에서 사용하는 Spring Security의 구성요소

 

🍰 SecurityContextHolder

Spring Security가 인증한 대상에 대한 디테일을 저장하는 곳이다.

SpringContextHolder

 

 

🍰 SecurityContext

SecurityContextHolder에서 가져와진다. 현재 인증된 사용자의 인증을 포함한다.

 

 

🍰 Authentication

AuthenticationManager의 입력으로 사용된다.

사용자 인증을 위해 제공한 credential이나 SecurityContext에 있는 현재 사용자의 credential을 제공한다.

Authentication이 가지고 있는 정보들

  • principal : 사용자를 식별한다. username/password로 인증할 때 주로 UserDetails의 인스턴스를 이용한다.
  • credentials : 일반적으로 password를 사용한다. (유출되지 않도록 인증 후 비운다.)
  • authorities : 사용자에게 부여한 권한은 grantedAuthority로 추상화한다.

 

 

🍰 GrantedAuthority

Authentication에서 principal(주체)에게 부여된 authority(권한)이다. (역할, 범위 등)

Authentication.getAuthorities() 메서드는 GrantedAuthority 객체들을 Collection으로 리턴한다.

권한은 보통 역할(roles)이다. (예 : "ROLE_ADMINISTRATOR", "ROLE_HR_SUPERVISOR")

이런 역할들은 나중에 웹 권한 부여, 메서드 권한 부여 및 도메인 객체 권한 부여를 위해 구성된다.

username/password 기반 인증을 사용한다면 UserDetailsServiceGrantedAuthority를 로드한다.

GrantedAuthority 객체는 애플리케이션 전체에 걸친 권한을 의미한다. (특정 도메인으로 한정하는 목적으로 사용하진 않는다.)

 

 

🍰 AuthenticationManager

Spring Seuciry의 필터가 어떻게 인증을 수행하는지에 대한 방법을 정의하는 API이다.

  • AuthenticationManager를 호출한 객체(Filter)가 리턴한 AuthenticationSecurityContextHolder에 설정한다.
  • Spring Security의 Filters를 사용하지 않을 경우 AuthenticationManager를 사용하지 않고 SecurityContextHolder에 직접 설정하면 된다.
  • AuthenticationManager의 가장 많이 사용하는 구현체는 ProviderManager이다.

 

 

🍰 ProviderManager

AuthenticationManager의 가장 일반적인 구현체이다.

  • ProviderManager는 동작을 AuthenticationProvider List에 위임한다.
  • 모든 AuthenticationProvider는 인증을 성공 or 실패 or 결정을 내릴 수 없는 지를 판단하고 다운스트림에 있는 AuthenticationProvider가 결정하게 할 수 있다.
  • 설정한 AuthenticationProvider들 중 어떤 것도 인증할 수 없다면, ProviderNotFoundException 오류와 함께 인증이 실패한다.
  • ProviderNotFoundException : ProviderManager가 전달된 Authentication 유형을 지원하도록 구성되지 않았음을 나타낸다.
  • AuthenticationProvider마다 각자 맡은 인증을 수행한다.

 

ProviderManager

 

  • ProviderManager에 인증을 수행할 AuthenticatinoProvider가 없을 경우, 부모 AuthenticationManager 구성을 허용한다.
  • 부모는 어떤 타입의 AuthenticationManager든 가능하지만 주로 ProviderManager의 인스턴스이다.

 

ProviderManager - AuthenticationManager

 

  • 여러 개의 SecurityFilterChain 인스턴스가 공통의 인증(같은 부모 AuthenticationManager)을 가지지만 다른 인증 매커니즘(다른 ProviderManager 인스턴스)일 경우 같은 부모 AuthenticationManager를 여러 ProviderManager가 공유할 수 있다.

 

multiple ProviderManager

 

  • ProviderManager는 인증 이후의 리턴된 Authentication 객체의 모든 민감한 credential 정보는 제거하려고 시도한다.
  • password와 같은 정보가 HttpSession에 필요 이상으로 오래 남아있는 것을 방지하기 위해서이다.
  • 하지만 Authentication에 cache의 객체(ex. UserDetails)에 대한 참조가 포함되어 있는 경우 credential 정보를 모두 제거하면 캐시된 값에 대해 더 이상 인증할 수 없는 문제가 생길 수 있다.
  • 해결책은 캐시 구현 또는 반환된 Authentication 객체를 생성하는 AuthenticationProvider에서 먼저 객체의 복사본을 만드는 것이다.
  • 또 다른 해결책으로는 ProviderManagereraseCredentialsAfterAuthentication property를 비활성화 하는것이다.

 

 

🍰 AuthenticationProvider

다수의 AuthenticationProviderProviderManager에 주입할 수 있다.

각각의 AuthenticationProvider는 특정 유형의 인증을 수행한다.

ex) DaoAuthenticationProvider : username/password 기반의 인증을 지원한다.

JwtAuthenticationProvider : JWT 토큰 인증을 지원한다.

 

 

🍰 Request Credentials with AuthenticationEntryPoint

AuthenticationEntryPoint는 클라이언트의 자격증명 요청에 대한 응답 HTTP를 보내는데 사용된다.

또한 클라이언트에 자격증명을 요청할 때 사용된다.

AuthenticationEntryPoint의 구현체는 로그인 페이지로 리디렉션하거나 WWW-Authenticate header를 전송하는 것을 수행한다.

 

 

🍰 AbstractAuthenticationProcessingFilter

사용자의 credentials를 인증하기 위한 기초 Filter로 사용된다.

credentials이 인증되기 전에, Spring Security는 일반적으로 AuthenticationEntryPoint를 사용하여 credentials을 요청한다.

여러 component를 조합하여 심도있는 인증 플로우를 구성할 수 있다.

 

 

 

 

참고) Servlet Authentication Architecture

참고) Spring Security doc

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 😃

 

 

 

반응형
반응형

 

 

 

 

 

 

🥧 Spring Security 란?

 

 

🍞 스프링 시큐리티(Spring Security)

 

Acegi Security(아시지 시큐리티) 프로젝트로 시작

➡️ 스프링 포트폴리오 프로젝트에 병합되면서 이름이 Spring Security로 바뀌었다.

 

🍰 Spring Security는 강력하고 커스텀 가능한 인증(Authentication)과 접근 통제(Access Control) 프레임워크이다.

🍰 스프링 기반의 애플리케이션에서 보안을 위한 표준이다.

🍰 모든 자바 애플리케이션에 적용 가능하지만 웹 애플리케이션에서 많이 쓰인다.

🍰 스프링 인터셉터, 필터 기반의 보안 기능을 구현하는 것보다 스프링 시큐리티를 통해 구현하는 것을 권장하고 있다.

🍰 확장성 : 다양한 요구사항을 손쉽게 추가하고 변경할 수 있다.

🍰 실행하려면 Java 8 이상의 환경이 필요

 

 

 

🍞 필수 용어 및 개념

 

🥞 주체 (Principal)

🍰 유저, 기기, 시스템 등이 될 수 있지만 보통 유저(사용자)를 의미한다.

 

🥞 인증 (Authentication)

🍰 특정 리소스에 접근하려고 하는 사용자가 누구인지 확인할 때 사용한다.

🍰 주체의 신원(identity)을 증명하는 과정

🍰 주체는 자신을 인증해달라고 신원 증명 정보(credential)을 제시한다.

🍰 주체가 유저일 경우 신원 증명 정보는 패스워드이다.

 

🥞 인가 (Authorization, 권한 부여)

🍰 인증을 마친 유저에게 권한(authority)을 부여하여 애플리케이션의 특정 리소스에 접근할 수 있게 허가하는 과정

🍰 인가는 반드시 인증 과정 이후 수행되어야 하며 권한은 롤 형태로 부여하는게 일반적이다.

 

🥞 접근통제 (Access control)

🍰 어떤 유저가 애플리케이션 리소스에 접근하도록 허락할 지를 제어하는 행위

🍰 접근 통제 결정(access control decision)이 뒤따른다.

🍰 리소스의 접근 속성과 유저에게 부여된 권한 또는 다른 속성들을 결정한다.

 

 

 


 

 

🥧 Spring Security를 배워야 하는 이유

 

 

🍞 Spring Security 특징

 

🍰 모든 요청에 대해서 인증을 요구한다.

🍰 사용자 이름 및 암호를 가진 사용자가 양식 기반으로 인증할 수 있도록 허용한다.

🍰 사용자의 logout을 허용한다. ➡️ LogoutFilter로 코드의 구현없이도 간편하게 로그아웃을 지원한다. 커스텀도 가능하다.

🍰 CSRF(Cross-site Request Forgery) 공격을 방지한다.

🍰 Session Fixation(세션 고정 공격)을 보호한다.

🍰 보안 헤더 통합

  • HSTS(HTTP Strict Transport Security) 강화
  • X-Content-TypeOptions
  • 캐시 컨트롤(정적 리소스 캐싱)
  • X-XSS-Protection XSS 보안 : 스크립트 공격 보안
  • 클릭재킹을 방지하는 X-Frame 옵션 통합

🍰 Servlet API 제공

 

 

※ Session Fixation (세션 고정 공격)

세션 고정이란 공격자가 유효한 사용자 세션을 가로채도록 허용하는 공격을 말한다.

로그인 시 발급받은 sessionID가 로그인 전후로 모두 동일하게 사용되어 악의적인 사용자가 피해자의 세션을 하이제킹하여 정상적인 사용자로 위장하여 접근한다.

공격자가 유효한 session ID를 얻음 ➡️ 사용자가 공격자의 session ID로 자신을 인증하도록 유도 ➡️ 사용된 session ID를 통해 사용자 검증된 세션을 하이재킹

세션에 대한 만료나 서로 다른 IP의 동일한 세션에 대해 취약한 웹 애플리케이션의 경우 이용하는 다수의 사용자가 해당 공격에 노출될 가능성이 존재한다.

 

참고) OWASP

참고) Session Fixation(세션 고정) 취약점

 

 

※ HSTS(HTTP Strict Transport Security) 기능

HTTP Strict-Transport-Security response header

HTTP 대신 HTTPS만을 사용하여 통신해야한다고 웹사이트가 브라우저에 알리는 보안 기능이다.

통신에서 일부분 HTTP를 사용할 경우 sessionID나 쿠키등이 해커에게 탈취되었을 경우 그대로 데이터가 노출이 되지만 HTTPS를 사용할 경우엔 데이터가 노출되는 것을 막을 수 있다.

만약 웹사이트가 HTTP 요청을 받고 HTTPS로 리다이렉트 하는 경우에, 유저가 http 또는 도메인만 입력한 경우에 리다이렉트 되기 이전의 암호화되지 않은 버전의 사이트와 통신하게 된다. 이경우, 악의적인 다른 페이지로 리다이렉트 되는 man-in-the-middle attack의 잠재적 위험이 있다.

HTTP Strict Transport Security 헤더는 웹사이트가 브라우저에게 절대로 HTTP로 사이트를 연결하면 안되고 HTTP로 연결하려는 모든 시도는 자동으로 HTTPS로 변경해야 한다고 알린다.

 

참고) mdn web docs

참고) HSTS

 

 

※ 클릭재킹

클릭재킹이란 웹 사용자가 자신이 클릭하고 있다고 인자하는 것과 다른 것을 클릭하게 속이는 해킹 기법이다.

공격자는 비밀 정보를 유출시키거나 컴퓨터에대한 제어를 획득할 수 있게 된다.

 

 

※ Cache-Control

header 필드

request와 response 내의 캐싱 정하기 위해 사용된다.

 

 

참고) mdn web docs

 

 


 

 

🥧 Spring Security 환경 구성

 

config 패키지와 SecurityConfig.java 파일 생성

 

  • @Configuration , @EnableWebSecurity 추가
  • @EnableWebSecurity : spring security 필터체인에 등록된다.

 

 

🥞 http.csrf().disable()

form 태그로만 요청이 가능하고 postman 등의 요청이 불가능하게 된다.

 

 

🥞 http.headers().frameOptions().disable()

h2 연결할 때 필요하다.

 

 

🥞 BCryptPasswordEncoder 클래스

PasswordEncoder를 구현한 클래스이고 강력한 해시 함수인 BCrypt 를 사용한다.

 

※ 참고) bcrypt

블로피시 암호에 기반을 둔 암호화 해시 함수

레인보우 테이블 공격 방지를 위해 salt를 추가한 적응형 함수의 하나이다.

 

 

🥞 @EnableGlobalMethodSecurity

Spring Security 의 전역 메서드 보안을 활성화한다.

 

✅ 옵션

1. securedEnabled : Secured 애너테이션 활성화 여부를 결정한다.

2. prePostEnabled : Spring Security의 pre/proAuthorize 애너테이션을 활성화한다.

3. jsr250Enabled : @RoleAllowed 애너테이션을 사용할 수 있도록 해준다.

 

 

🥞 @Secured

1개의 권한을 줄 때 사용

@Secured(“ROLE_ADMIN”)

 

 

🥞 @PreAuthorize

 

1개 이상의 권한을 줄 때 사용

#을 이용해서 파라미터에 접근할 수 있다.

 

@PreAuthorize(“hasRole(‘ROLE_MANAGER’) or hasRole(‘ROLE_ADMIN’)”)

 

@PreAuthozie(“isAuthenticated() and ((#user.name == principal.name) or hasRole(‘ROLE_ADMIN’))”)

 

 

 

🥞 @PostAuthorize

 

메서드가 실행되고 응답하기 직전에 권한을 검사하는데 사용

클라이언트에 응답하기 전에 로그인 상태 또는 반환되는 사용자 이름과 현재 사용자 이름에 대한 검사, 현재 사용자가 관리자 권한을 가지고 있는지 등의 권한 후처리를 한다.

 

 


 

 

🥧 Filter와 FilterChain

 

 

🍞 Filter

 

Spring Filter

 

Spring Security는 Servlet Filter를 기반으로 서블릿을 지원한다.

Filter : HTTP 요청과 응답을 변경할 수 있는 재사용 가능한 코드이다.

 

  • 클라이언트가 서버로 요청을 하게되면 가장 먼저 Servlet Filter를 거치게 된다.
  • Filter를 거치고 나면 Servlet(DispatcherServlet)에서 요청이 처리된다.
  • Spring Security는 주요 보안에 대한 처리를 여러가지 Filter로 처리하도록 구성되어 있다.
  • 인증(Authentication)과 인가(Authorization)에 대한 처리를 Filter에서 한다.
  • 자동 설정 옵션을 사용하면 10개의 스프링 시큐리티 필터가 자동으로 설정된다.

 

 

 

🍞 FilterChain

 

Filter Chain

 

단일 HTTP 요청을 처리하는 전형적인 레이어

여러개의 Filter들이 사슬처럼 연결되어 서로 연결되어 동작한다.

 

 

🥞 FilterChain의 특징

 

🍰 클라이언트가 앱에 요청을 보내고 컨테이너는 요청 URI의 경로를 기반으로 어떤 필터와 어떤 서블릿을 적용할지 결정한다.

🍰 하나의 서블릿은 단일 요청을 처리하지만 필터는 체인을 형성하여 순서를 지정하며 실제로 요청 자체를 처리하려는 경우 필터가 나머지 체인을 거부할 수 있다.

🍰 필터는 다운스트림 필터와 서블릿을 사용해서 요청과 응답을 수정할 수도 있다.

🍰 필터 체인의 순서는 매우 중요하며 Spring Boot는 두 가지 매커니즘을 통해 이를 관리한다. 하나는 Filter 타입의 @Beans 에 @Order를 붙이거나 Ordered를 구현하는 것이고 다른 하나는 API의 일부로 순서를 가지는 FilterRegistrationBean의 일부가 되는 것이다.

🍰 클라이언트는 애플리케이션으로 요청을 전송하고 컨테이너는 Servlet과 여러 Filter로 구성된 FilterChain을 만들어 요청 URI path 기반으로 HttpServletRequest를 처리한다.

🍰 Filter는 요청이 DispatcherServlet에 의해 다뤄지기 전, 후에 동작한다.

🍰 Filter는 FilterChain을 통해 여러 필터가 연쇄적으로 동작하게 할 수 있다.

🍰 1개의 Servlet이 HttpServletRequest와 HttpServletResponse 처리를 담당한다.

  • Filter는 여러개 사용할 수 있다.
  • 다운 스트림의 Servlet과 Filter의 실행을 막는다. (보통 이 경우 Filter에서 HttpServletResonse를 작성한다.)
  • 다운 스트림에 있는 Servlet과 여러 Filter로 HttpServletRequest나 HttpServletResponse를 수정한다.

🍰 Filter는 FilterChain 안에 있을 때 효력을 발휘한다.

 

 

 

🥞 Filter Interface

 

  • public void init(FilterConfig filterConfig) throws ServletException 필터를 웹 컨테이너 내에 생성한 후 초기화 할 때 호출한다.
  • public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException 체인을 따라 다음에 존재하는 필터로 이동한다.
  • 체인의 가장 마지막에는 클라이언트가 요청한 최종 자원이 위치한다.
  • public void destroy() 필터 : 웹 컨테이너에서 삭제될 때 호출된다.
  • doFilter() : 필터의 역할을 하는 메서드

 

 

 

🥞 FilterRegistrationBean 옵션

 

FilterRegistrationBean의 옵션으로 Filter에 여러가지 옵션을 추가할 수 있다.

 

🥑 addUrlPatterns

registrationBean.addUrlPatterns(“/users/*”);

setUrlPatterns와 비슷하다.

/users/ 로 시작하는 url로 요청이 오게되면 필터를 통과한다.

 

🥑 setOrder

registrationBean.setOrder(1);

필터의 실행 순서를 지정한다.

 

 

 

🍞 DelegatingFilterProxy

 

DelegatingFilterProxy

 

Spring Security가 모든 애플리케이션 요청을 감싸게 해서 모든 요청에 보안이 적용되게 하는 ServletFilter이다.

스프링 프레임워크 기반의 웹 애플리케이션에서 서블릿필터 라이프 사이클과 연계해 스프링 빈 의존성을 서블릿 필터에 바인딩하는데 사용한다.

 

  • 스프링 부트는 DelegatingFilterProxy(Filter 구현체)로 서블릿 컨테이너의 생명주기와 스프링 ApplicationContext를 연결한다.
  • Servlet Container는 자체 표준을 사용해서 Filter를 등록할 수 있지만 스프링이 정의하는 Bean은 인식하지 못한다.
  • DelegatingFilterProxy는 표준 서블릿 컨테이너 매커니즘으로 등록할 수 있으면서도 모든 처리를 Filter를 구현한 스프링 빈으로 위임한다.
  • DelegatingFilterProxy는 ApplicationContext에서 Bean Filter0를 찾아 실행한다.
  • Bean Filter0는 FilterChainProxy가 된다.

 

 

 

🍞 FilterChainProxy

 

Spring Security는 FilterChainProxy로 서블릿을 지원한다.

 

FilterChain Proxy

 

  • FilterChainProxy는 Spring Security가 제공하는 특별한 Filter로 SecurityFilterChain을 통해 여러 Filter 인스턴스로 위임할 수 있다.
  • FilterChainProxy는 빈이기 때문에 보통 DelegatingFilterProxy로 감싸져 있다.
  • DelegatingFilterProxy는 서블릿 필터이며, Spring IOC 컨테이너가 관리하는 Filter Bean을 갖고있다.
  • Filter Bean은 FilterChainProxy이며 이 객체안에서 Security와 관련된 일들이 벌어진다고 생각할 수 있다. (위 그림에서의 DelegatingFilterProxy안에 Bean Filter는 FilterChainProxy가 된다.)

 

순수한 Servlet Filter는 본래 Spring Container 외부에 존재한다.

DelegatingFilterProxy 클래스는 Filter를 Spring Bean으로 사용할 수 있다.

DelegatingFilterProxy 클래스(Filter Class)는 Servlet Filter 사이에 존재하고 Spring Bean으로 등록된 Filter에게 처리를 위임한다.

 

 


 

 

🥧 DelegatingPasswordEncoder

 

 

🍞 DelegatingPasswordEncoder 란?

 

Spring Security 5.0 버전 이전에 PasswordEncoder의 기본값인 NoOpPasswordEncoder는 일반 텍스트 비밀번호를 사용했다.

비밀번호 히스토리 세션을 기반으로 PasswordEncoder 기본값이 이제 BCryptPasswordEncoder 같은 것으로 바뀌었다.

하지만 다음의 3가지 문제가 존재한다.

  • 애플리케이션이 마이그레이션(이식)이 쉽지 않은 옛날 방식으로 비밀번호를 인코딩하는 경우
  • 비밀번호를 저장하기 위한 관행이 다시 변경될 수 있음
  • Spring Security는 프레임워크로서 자주 변경사항을 변경할 수 없다.

 

대신에 Spring Security는 위의 문제를 해결할 DelegatingPasswordEncoder를 도입했다.

  • 비밀번호를 최신 저장 권장방법으로 인코딩되었는지 확인한다.
  • 최신 및 레거시 형식의 암호 유효성 검사를 허용한다.
  • 향후 인코딩 업그레이드를 허용한다.

 

 

참고) Baeldung Spring Method Security

참고) Spring Security doc

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 😁

 

 

반응형
반응형

 

 

 

 

 

🧊 프록시 서버(Proxy Server)

 

 

Proxy는 대리라는 뜻

클라이언트가 서버와 소통할 때 서버와 바로 통신하지 않고 프록시 서버를 통해 서버에 접근할 수 있다. ➡️ 대리 서버

 

일반 사용자는 지역이 제한되어 있는 서비스를 이용하기 위해 IP를 우회하거나, 캐시를 통해 더 빠른 이용을 하기 위해 프록시 서버를 사용한다.

 

 

🍹 프록시 서버의 종류

 

위치에 따라 Forward ProxyReverse Proxy 두가지로 나뉜다.

 

 

 

🍺 Forward Proxy

 

Forward Proxy

 

클라이언트 가까이에 위치한 프록시 서버

클라이언트를 대신해 서버에 요청을 전달한다.

주로 캐싱을 제공하는 경우가 많아 사용자가 빠른 서비스 이용을 할 수 있도록 도와준다.

 

 

➡️ Forward Proxy를 사용할 경우 이점

 

✅ 캐싱을 통해 빠른 서비스 이용 가능

여러 클라이언트가 동일한 요청을 보내는 경우 첫 응답 결과 데이터를 캐시에 저장해놓고, 이후 서버에 재요청을 보내지 않아도 다른 클라이언트에게 빠르게 전달할 수 있다.

 

✅ 보안

서버에서 클라이언트의 IP추적이 필요한 경우 클라이언트의 IP가 아닌 프록시 서버의 IP가 전달된다. 서버가 응답받은 IP는 프록시 서버의 IP이기 때문에 서버에게 클라이언트를 숨길 수 있다.

 

 

 

🍺 Reverse Proxy

 

Reverse Proxy

 

서버 가까이에 위치한 프록시 서버이다.

서버를 대신하여 클라이언트에 응답을 제공한다.

 

 

➡️ Reverse Proxy 사용할 경우 이점

 

✅ 분산처리

클라이언트-서버 구조에서 사용자가 많아져 서버에 과부하가 올 경우를 위해 부하를 분산할 수 있다. 프록시 서버로 요청이 들어오면 여러대의 서버로 요청을 나누어 전달한다.

 

✅ 보안

Forward Proxy와는 반대로 클라이언트에게 서버를 숨길 수 있다. 클라이언트 입장에서는 요청을 보내는 서버가 프록시 서버이므로 실제 서버 IP 주소가 노출되지 않는다.

 

 

 

🧊 로드밸런서

 

웹 서버로 너무 많은 사용자가 요청을 보낼 경우 서버는 감당하지 못하고 과부하가 오게 된다.

과부하가 올 경우 서비스를 정상적으로 제공하지 못하는 문제가 생긴다.

이를 해결하기 위해 서버의 하드웨어를 업그레이드 하는 방법과 서버의 개수를 늘리는 방법이 있다.

 

 

 

🍹 Scale-Up

 

물리적으로 서버의 사양을 업그레이드하는 방법이다. (HDD, 메모리 등)

수직적 스케일링

 

🍺 장점

서버의 수를 늘리지 않고 프로그램 구현에 있어 변화가 필요없다.

 

🍺 단점

서버의 사양을 높이는 데는 굉장히 높은 비용이 든다.

하드웨어의 업그레이드에는 한계가 있다.

 

 

🍹 Scale-Out

 

서버의 개수를 늘려 하나의 서버에 줄 부하를 분산시키는 방법이다.

수평적 스케일링

많은 요청이 오더라도 여러대의 서버가 나눠서 처리를 하기 때문에 서버의 사양을 높이지 않고도 비교적 저렴한 방법으로 부하를 처리할 수 있다.

 

Scale-Out 방법으로 서버를 여러대 있을 경우 서버에 요청을 나눠 처리할 수 있는 역할이 필요하다. ➡️ 로드 밸런서

여러 서버에 교통정리를 해주는 기술 혹은 프로그램을 로드 밸런싱이라고 부른다.

 

※ 추가학습) Scale-Up vs Scale-Out

 

 

 

🍹 로드 밸런서 종류

 

클라이언트의 요청을 어떤 기준으로 분산하냐에 따라 네종류로 나뉜다.

 

L2 : 데이터 전송 계층에서 Mac 주소를 바탕으로 로드 밸런싱한다.

L3 : 네트워크 계층에서 IP 주소를 바탕으로 로드 밸런싱한다.

L4 : 전송 계층에서 IP주소와 Port를 바탕으로 로드 밸런싱한다.

L7 : 응용 계층에서 클라이언트의 요청을 바탕으로 로드 밸런싱한다. ex) 엔드포인트

 

 

 

 

🧊 오토스케일링 (AWS의 Auto Scaling 기준)

 

오토스케일링은 Scale-Out 방식으로 서버를 증설할 때 자동으로 서버(리소스)를 관리해주는 기능이다.

클라이언트의 요청이 많아져 서버의 처리 요구량이 증가하면 새 리소스를 자동으로 추가하고 반대로 처리 요구량이 줄어들면 리소스를 감소시켜 효율적으로 관리해준다.

 

 

🍹 Auto Scaling의 장점

 

🍺 동적 스케일링

사용자의 요구 수준에 따라 리소스를 동적으로 스케일링 할 수 있다.

스케일 업 할 수 있는 서버의 수에 제한이 없고, 필요한 경우 즉시 수백~수만대로 늘릴 수 있다.

 

🍺 로드 밸런싱

로드 밸런서와 함께 사용하면, 다수의 EC2 인스턴스에게 워크로드를 효과적으로 분배할 수 있다. 사용자가 정의한 규칙에 따라 워크로드를 효과적으로 관리할 수 있다.

워크로드(Workloads) :  애플리케이션이나 백엔드 프로세스 같이 비즈니스 가치를 창출하는 리소스 및 코드 모음

 

🍺 타겟 트래킹

사용자는 특정 타겟에 대해서만 Auto Scaling을 할 수 있다.

사용자가 설정한 타겟에 맞춰 EC2 인스턴스의 수를 조정한다.

 

🍺 헬스 체크와 서버 플릿 관리

EC2 인스턴스의 헬스 체크 상태를 모니터링 할 수 있다.

특정 인스턴스의 문제가 감지되면 자동으로 다른 인스턴스로 교체한다.

 

 

서버 플릿(Fleet)

Fleet은 직역하면 함대라는 의미이다.

다수의 EC2 서버에서 애플리케이션을 호스팅하는 경우,

호스팅하고 있는 일련의 EC2 집합을 AWS는 서버 플릿(Fleet)이라고 부른다.

Auto Scaling은 적정 수준의 서버 플릿 용량을 유지하는데 도움을 준다.

Auto Scaling은 한대 또는 그 이상의 서버가 다운되면 서버 인스턴스 처리용량을 유지하기 위해 부족한 만큼 새로운 서버를 추가로 실행시키는 방식으로 서버 플릿을 유지한다.

 

※ 참고자료) EC2 Fleet 설명서

 

 

 

🍹 EC2 Auto Scaling 활용

 

Auto Scaling은 EC2 인스턴스 뿐만 아니라 다른 인스턴스와도 결합이 가능하다.

EC2 Auto Scaling은 오직 EC2 서버(리소스)만 대상으로 한다.

 

 

🍺 시작 템플릿(Launch Template)

시작 템플릿을 통해서 인스턴스를 확장할 때 구성 정보를 쉽게 적용할 수 있다.

인스턴스를 늘릴 때마다 매번 parameter들을 설정할 필요없이 시작 템플릿으로 쉽게 설정하고 확장할 수 있다.

시작 템플릿은 AMI ID, 인스턴스 타입, 네트워크 세팅 등의 인스턴스 생성시 필요한 정보를 담고 있다.

여러 시작 템플릿 버전을 만들어서 서로 다른 launch parameter를 가진 템플릿을 여러개 만들수있다.

 

※ AWS 공식문서

 

 

🍺 Auto Scaling 그룹

 

스케일업 및 스케일다운 규칙의 모음이다.

EC2 인스턴스 시작부터 삭제하기까지의 모든 동작에 대한 규칙과 정책을 담고 있다.

 

 

🍺 Scaling 유형

 

🥑 인스턴스 레벨 유지

기본 스케일링 계획이라고 불린다.

항상 실행 상태를 유지하고자 하는 인스턴스의 수를 지정할 수 있다.

일정한 수의 인스턴스가 필요한 경우 최소, 최대, 원하는 용량에 동일한 값을 설정할 수 있다.

 

🥑 수동 스케일링

기존 Auto Scaling 그룹의 크기를 수동으로 변경할 수 있다.

수동 스케일링을 선택하면 사용자가 직접 콘솔이나, API, CLI 등을 이용해 수동으로 인스턴스를 추가하거나 삭제해야 한다. 이 방식은 추천하지 않는 방식이다.

 

🥑 일정별 스케일링

예측 스케일링 트래픽의 변화를 예측할 수 있고, 특정 시간대에 어느 정도의 트래픽이 증가하는지 패턴을 파악하고 있다면 일정별 스케일링을 사용하는 것이 좋다.

 

🥑 동적 스케일링

수요 변화에 대응하여 Auto Scaling 그룹의 용량을 조절하는 방법을 정의한다.

CloudWatch가 모니터링 하는 지표를 추적하여 경보 상태일 때 수행할 스케일링 규칙을 정한다.

예를 들어 CPU 처리 용량의 80% 수준까지 급등한 상태가 5분 이상 지속될 경우 Auto Scaling이 작동돼 새 서버를 추가한다.

동적 스케일링 정책을 정의할 때는 스케일 업과 스케일 다운 두 가지의 정책을 작성해야 한다.

 

 

 

 

🧊 TOMCAT

 

Tomcat

 

🍹 Tomcat 이란?

 

Apache사에서 개발한 서블릿 컨테이너만 있는 오픈소스 웹 애플리케이션 서버이다.

 

 

🍺 Tomcat의 특징

 

🥑 자바 애플리케이션을 위한 대표적인 오픈소스 WAS(Web Application Server)이다.

🥑 오픈소스이기 때문에 라이선스 비용 부담없이 사용할 수 있다.

🥑 독립적으로도 사용 가능하며 Apache 같은 다른 웹 서버와 연동하여 함께 사용할 수 있다.

🥑 Spring Boot의 내장 서버이기 때문에 별도의 설치 과정 없이 사용할 수 있다.

🥑 spring-boot-starter-web 모듈 속에 내장되어있다.

 

 

 

🧊 Jetty

 

jetty

 

🍹Jetty 란?

 

Jetty는 이클립스 재단의 HTTP 서버이자 자바 서블릿 컨테이너 이다.

 

 

🍺 Jetty의 특징

 

🥑 2009년 이클립스 재단으로 이전하며 오픈소스 프로젝트로 개발되었다.

🥑 Jetty는 타 웹 애플리케이션 대비 적은 메모리를 사용하여 가볍고 빠르다.

🥑 애플리케이션에 내장 가능하다.

🥑 경량 웹 애플리케이션으로 소형 장비, 소규모 프로그램에 더 적합하다.

 

 

🍹 Tomcat에서 Jetty로 서버 변경하기

 

build.gradle 파일

➡️ spring-boot-starter-web 의존성 추가된 부분에 Tomcat을 제외시켜준다.

dependencies {
	implementation ('org.springframework.boot:spring-boot-starter-web') {
		exclude module: 'spring-boot-starter-tomcat'
	}
}

 

Jetty 의존성을 추가한다.

implementation ('org.springframework.boot:spring-boot-starter-jetty')

 

Tomcat을 모듈에서 제외시켰고 Jetty 모듈을 추가했기 때문에 서버를 실행할 때 Jetty로 실행되는 것을 확인할 수 있다.

 

 

 

🧊 NGINX

 

NGINX

 

🍹 NGINX란?

 

🥑 NGINX는 가볍고 높은 성능을 보이는 오픈소스 웹 서버 소프트웨어이다.

🥑 Igor Sysoev 라는 러시아 개발자가 개발했다.

🥑 동시접속 처리에 특화된 웹 서버 프로그램이다.

🥑 Apache보다 동작이 단순하고 전달자 역할만 하기 때문에 동시접속 처리에 특화되어 있다.

🥑 Nginx는 클라이언트에게 정적 리소스를 빠르게 응답 하기 위한 웹 서버로 사용할 수 있다.

 

 

🍺 NGINX의 특징

 

🥑 트래픽이 많은 웹 사이트의 확장성을 위해 개발된 고성능 웹 서버이다.

🥑 비동기 이벤트 기반으로 적은 자원으로 높은 성능과 높은 동시성을 위해 개발되었다.

🥑 다수의 클라이언트 연결을 효율적으로 처리할 수 있다.

🥑 클라이언트와 서버 사이에 존재하는 리버스 프록시 서버로 사용할 수 있다.

🥑 Nginx를 클라이언트와 서버 사이에 배치하여 무중단 배포를 할 수 있다.

 

 

🍹 Spring Boot와 Nginx 연동하기

 

nginx를 이용해서 Spring Boot 앞에 프록시 서버를 구축할 수 있다.

그래서 클라이언트가 실제로 통신하는 포트를 Spring Boot 서버와 분리할 수 있다.

 

클라이언트 - NGINX - Spring Boot

 

 

🍺 NGINX 설치 및 실행 (Mac OS)

 

✅ 설치

brew install nginx

 

✅ 실행

brew services start nginx

 

✅ 중단

brew services stop nginx

 

 

 

🍺 NGINX 설정 파일(.conf 파일) 찾기

 

nginx의 설정파일(.conf 파일)로 여러가지 설정을 변경할 수 있다.

(사용할 포트번호, 연결할 서버의 포트 번호 등)

 

✅ 설정파일 위치 찾기

nginx -t

 

텍스트 편집기 실행 후 설정 변경

nano /opt/homebrew/etc/nginx/nginx.conf

 

 

 

🍺 NGINX로 Proxy Server 만들기

 

설정파일에 아래와 같이 코드 작성

 

http {
	...
	server{
		listen 80; #8080 포트에서 80번 포트로 변경한다
		...
		location / {
			root html;
			index index.html index.htm;
			proxy_pass http://localhost:8080; # 요청을 8080 포트로 전달한다
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header Host $http_host;
		}
		...
	}
}

 

 

설정파일 수정 뒤에는 재시작을 해준다.

brew services restart nginx

 

 

 

🍹 NGINX를 Load Balancer로 활용하기

 

 

NGINX를 통해 로드밸런싱을 구성할 수 있다.

로드밸런싱에 추가할 서버를 실행한다.

NGINX 설정 파일에 들어가서 서버 그룹을 만들고 해당 서버 포트 번호를 추가해준다.

 

http {
	upstream backend {
		server localhost:{포트번호1};	#로드밸런싱할 서버1
		server localhost:{포트번호2};	#로드밸런싱할 서버2
		...
	}
	location / {
		proxy_pass http://backend;
	}
}

 

upstream 뒤에 적은 backend는 지정한 서버 그룹이름이다.

원하는 그룹이름으로 적으면 된다.

 

추가자료) nginx 공식 문서

 

 

 

 

🧊 VPC

 

 

🍹 VPC 란?

 

VPC : Vitual Private Cloud 서비스

클라우드 내 private 공간을 제공해서 클라우드를 public과 private 영역으로 논리적으로 분리할 수 있게 해준다.

 

 

 

🍹 VPC 구성 요소와 주요 용어

 

 

🍺 IP Address

 

IP는 컴퓨터 네트워크에서 장치들이 서로를 식별하기 위해 사용하는 특수한 번호이다.

OSI의 3계층인 네트워크 계층에 해당된다.

IPv4, IPv6로 나뉘어 있으며 혼용하여 사용하고 있다.

IPv4는 각 8비트, IPv6는 각 32비트로 4개의 옥텟으로 이루어져 있다.

네트워크 주소와 호스트 주소로 나뉘어 진다.

 

🌱 네트워크 주소 : 호스트들을 모은 네트워크를 지칭하는 주소이다. 네트워크 주소가 동일한 네트워크를 로컬 네트워크라고 한다.

🌱 호스트 주소 : 하나의 네트워크 내에 존재하는 호스트를 구분하기 위한 주소

 

네트워크 주소와 호스트 주소를 나누는 경계점이 고정되어 있지 않다.

IP주소는 네트워크 주소와 호스트 주소를 나누는 경계점에 따라 클래스(Class)를 나눈다.

호스트 IP 개수에 따라 네트워크의 크기를 다르게 할당할 수 있다.

클래스는 총 5가지(A, B, C, D, E)로 나뉘어져 있다.

D와 E 클래스는 멀티캐스트용, 연구 개발을 위한 예약 IP라서 보통은 사용하지 않는다.

 

A, B, C 클래스의 맨 앞자리 숫자만 보면 무슨 클래스인지 식별이 가능하다.

클래스풀(Classful) 방식이라고 부른다.

 

A 클래스

Network Address Host Address Host Address Host Address
0 ~ 127 0 ~ 255 0 ~ 255 0 ~ 255

0.0.0.0은 자체 네트워크를 의미하고 127.0.0.0 ~ 127.255.255.255는 자기자신을 가리키기 위해 예약된 IP 주소이기 때문에 사용할 수 없다.

 

B 클래스

Network Address Network Address Host Address Host Address
128 ~ 191 0 ~ 255 0 ~ 255 0 ~ 255

 

C 클래스

Network Address Network Address Network Address Host Address
192 ~ 223 0 ~ 255 0 ~ 255 0 ~ 255

 

모든 클래스의 맨 앞 주소는 네트워크 주소로, 맨 뒤 주소는 브로드캐스트 주소로 사용하므로 실제 사용할 수 있는 IP는 2^n - 2이다.

 

 

🍺 CIDR(Classless inter-domain routing)

 

클래스 없는 도메인 간 라우팅 기법으로 사이더라고 불린다.

국제 표준의 IP 주소 할당 방법이다.

클래스풀 방식을 대체한 방식이다.

 

기존에는 클래스에 따라 정해진 Network Address와 Host Address를 사용했지만 CIDR은 원하는 블록만큼 Network Address를 지정할 수 있다.

AWS의 VPC는 CIDR 방식이다.

 

ex) 172.16.0.0/24

-> /24 이 서브넷 블록, 네트워크 주소에 16비트만 할당한다는 의미이다. 총 2^인 개의 IP 주소를 사용할 수 있다.

 

AWS VPC에서는 /16 블록을 사용하도록 권장하고 있다.

※ 추가 자료) AWS VPC 기본 및 연결 옵션

 

 

🍺 서브넷(Subnet)

 

Subnetwork의 줄임말이다.

IP 네트워크의 논리적 하위 부분을 가리킴

서브넷을 통해 하나의 네트워크를 여러 개로 나눌 수 있음

VPC를 사용하면 필요에 따라 다양한 서브넷을 생성할 수 있음

  • 퍼블릭 서브넷: 인터넷을 통해 연결할 수 있는 서브넷
  • 프라이빗 서브넷: 인터넷을 연결하지 않고, 보안을 유지하는 배타적인 서브넷
  • VPN only 서브넷 : 기업 데이터 센터와 VPC를 연결하는 서브넷

 

VPC

 

서브넷은 VPC의 CIDR 블록을 이용해 정의된다.

최소 크기의 서브넷은 /28 이다.

서브넷은 AZ(Availability Zone, 가용 영역)당 최소 하나를 사용할 수 있고, 여러 개의 AZ에 연결되는 서브넷은 만들 수 없다.

 

AWS가 확보한 서브넷 중 처음 네 개와 마지막 IP 주소는 인터넷 네트워킹을 위해 예약되어 있다. 예를 들어 10.0.0.0/24 체계의 CIDR 블록이 있는 서브넷에서 10.0.0.0, 10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.255 는 IP 주소가 예약되어 있다.

 

 

🍺 라우팅 테이블(Routing Table)

 

트래픽의 전송 방향을 결정하는 라우트와 관련된 규칙을 담은 테이블이다.

목적지까지 최적의 경로로 데이터 패킷을 전송하기 위한 모든 정보를 담고 있다.

모든 서브넷은 라우팅 테이블을 가진다.

하나의 테이블 규칙을 여러 서브넷에 연결할 수 있다.

서브넷 생성 후 별도의 라우팅 테이블을 생성하지 않으면 클라우드가 자동으로 VPC의 메인 라우팅 테이블과 연결한다.

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

🍙 애플리케이션 빌드

 

 

🧁 IntelliJ IDE를 이용한 빌드

 

Spring Boot는 Gradle 빌드 툴을 이용해서 애플리케이션을 빌드할 수 있는 툴을 지원한다.

IntelliJ 에서 Gradle 탭을 누르고

Task ➡️ build ➡️ bootjar or build

로 손쉽게 빌드할 수 있다.

 

빌드가 정상적으로 완료되면

build/libs 디렉토리에 Jar 파일이 생성된다.

생성된 Jar 파일이 로컬에서 애플리케이션을 실행가능한 실행파일이다.

 

 

🧁 Gradle Task를 이용한 빌드

 

IntelliJ 같은 IDE가 설치되지 않은 환경에서 빌드를 해야하는 경우도 있다.

CLI 환경에서 빌드할 때는 프로젝트 최상위 경로에서

./gradlew build

를 입력해주면 빌드된다.

BUILD SUCCESSFUL

라고 적힌다면 빌드가 완료된 것이다.

 

 

 

🍙 애플리케이션 실행

 

java -jar [jar파일명].jar

입력하면 애플리케이션이 실행된다.

 

 

 

🍙 애플리케이션 배포

 

Spring Boot 기반의 실행 가능한 Jar(Executable Jar)을 서버에 배포해보자

 

 

🧁 전통적인 서버 배포 방법

 

Spring Boot 기반의 Executable jar 파일을 서버에 배포하기

scp, sftp 같은 표준 유닉스 툴을 사용해서 서버로 간단히 전송한다.

서버로 전송된 Jar파일은 JVM이 설치된 환경이라면 어디서든 쉽게 실행할 수 있다.

 

 

🧁 클라우드 서비스를 위한 배포 방법

 

Executable Jar 파일은 특히 클라우드 환경에서 손쉽게 배포할 수 있다.

 

 

▶️ PaaS(Platform as a Service)

 

대표적 예시 : Cloud Foundry, Heroku

 

▶️ IaaS(Infrastructure as a Service)

  • Executable Jar 는 AWS Elastic Beanstalk, AWS Container Registry, AWS Code Deploy 같은 서비스를 이용해서 손쉽게 배포가능하다.
  • Microsoft에서도 Azure 클라우드 서비스인 Azure Spring Cloud, Azure App Service 에서 배포 가능하다.
  • Google Cloud 에서도 Executable Jar 파일 배포를 위한 여러가지 옵션을 제공한다.

 

▶️ CI / CD 플랫폼을 사용한 배포

  • Github Actions, Circle CI
  • AWS나 Azure 같은 클라우드 서비스에 Executable Jar 파일을 자동 배포하도록 구성할 수 있다.

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

API 문서화

 

 

➤ API 문서화란?

 

API 문서화란 클라이언트가 REST API 백엔드 애플리케이션에 요청을 전송하기 위해서 알아야 되는 요청 정보(요청 URL 또는 URI, request body, query parameter 등)를 문서로 잘 정리하는 것을 의미한다.

 

 

▶️ API 요청을 위해 필요한 정보를 문서로 정리해야 하는 이유는 무엇인가?

 

백엔드에서 만든 REST API 기반의 애플리케이션을 클라이언트 쪽에서 사용하려면 API 사용을 위한 정보가 필요하기 때문이다.

 

API 사용을 위한 정보가 담겨 있는 문서를 API 문서 또는 API 스펙(사양, Specification)이라고 한다.

 

 

▶️ API 문서를 만드는 방법

 

🥑 개발자가 수기로 작성 ➡️ 비효율적!, 기능을 빠뜨릴 수 있음!

🥑 애플리케이션 빌드를 통해 API 문서를 자동으로 생성

 

 

 

➤ Spring Rest Docs vs Swagger

 

 

▶️ Swagger의 API 문서화 방식

 

🍋 Swagger는 API 문서 자동화 오픈 소스이다.

🍋 Java 기반의 애플리케이션에서는 전통적으로 Swagger를 많이 사용해왔다.

🍋 많은 양의 애너테이션이 추가된다. ➡️ 가독성이 떨어짐

🍋 코드가 길어지면 그만큼 API 문서화를 위한 코드도 길어진다. ➡️ 유지보수성이 떨어짐

🍋 Controller 뿐만 아니라 DTO 클래스에도 애너테이션을 일일이 추가해주어야 한다.

🍋 Swagger 기반의 API 문서는 [Excute] 라는 버튼하나로 Controller에 요청을 전송할 수 있다. ➡️ API 요청 툴로서 기능을 사용할 수 있다.

 

 

▶️ Spring Rest Docs의 API 문서화 방식

 

🍑 애플리케이션 기능 구현과 관련된 코드에 API 문서 생성을 위한 애너테이션과 같은 정보를 추가하지 않는다.

🍑 Controller 테스트 클래스에 API 문서화를 위한 정보가 추가된다.

🍑 테스트 케이스의 실행결과가 “passed”로 만들지 않으면 API 문서 생성이 완료되지 않는다. ➡️ API 스펙 정보와 API 문서 정보의 불일치로 생길 수 있는 문제 방지

🍑 테스트 케이스에서 전송하는 API 문서 정보와 Controller에서 구현한 request body, response body, query parameter 등의 정보가 하나라도 일치하지 않으면 테스트 케이스 실행 결과가 “failed” 되면서 API 문서가 정상적으로 생성이 되지 않는다.

🍑 Swagger 처럼 API 호출할 수 있는 툴의 역할은 하지 못한다.

 

 

 

 

Spring Rest Docs

 

 

➤ Spring Rest Docs 란?

 

Rest API 문서를 자동으로 생성해주는 Spring 하위 프로젝트이다.

 

 

➤ Spring Rest Docs 의 API 문서 생성 흐름

 

Spring Rest Docs

 

 

1. 테스트 코드 작성

🍒 슬라이스 테스트 코드 작성

🍒 API 스펙 정보(Request Body, Response Body, Query Parameter 등) 코드 작성

 

 

2. test task 실행

🍒 작성된 슬라이스 테스트 코드를 실행한다.

🍒 하나의 테스트 클래스를 실행시켜도 되지만 일반적으로 Gradle의 build task 중 하나인 test task 를 실행시켜서 API 문서 snippet(스니핏*)을 일괄 생성한다.

🍒 테스트 실행 결과가 “passed” 이면 다음 작업을 진행한다.

🍒 실행결과가 “failed” 일 경우 문제를 해결하기 위해 테스트 케이스를 수정한 뒤 다시 테스트를 진행한다.

 

※ 스니핏(snippet)

일반적으로 코드의 조각을 의미한다.

여기선 문서의 일부 조각을 의미한다.

테스트 케이스 하나당 하나의 스니핏이 생성되며, 여러개의 스니핏을 모아서 하나의 API 문서를 생성할 수 있다.

 

 

3. API 문서 스니핏(.adoc 파일) 생성

🍒 API 스펙 정보 코드를 기반으로 API 문서 스니핏이 .adoc 확장자를 가진 파일로 생성된다.

 

 

4. API 문서 생성

🍒 생성된 API 문서 스니핏을 모아서 하나의 API 문서로 생성한다.

 

 

5. API 문서를 HTML로 변환

🍒 생성된 API 문서를 HTML 파일로 변환한다.

🍒 HTML로 변환된 API 문서는 HTML 파일 자체를 공유해도 되고 URL을 통해 해당 HTML에 접속해서 확인할 수 있다.

 

 

 

➤ Spring Rest Docs 설정

 

1. build.gradle 설정

2. API 문서 snippet 을 사용하기 위한 템플릿 API 문서 생성

 

 

▶️ build.gradle 설정

 

API 문서를 자동으로 생성하기 위해 아래 설정 코드 추가

plugins {
	...
	id "org.asciidoctor.jvm.convert" version "3.3.2"
	...
}

...
ext {
	set('snippetsDir', file("build/generated-snippets"))
}

...
configurations {
	asciidoctorExtensions
}

dependencies {
	...
	testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
	asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
    ...
}

...
tasks.named('test') {
	outputs.dir snippetsDir
	useJUnitPlatform()
}

...
tasks.named('asciidoctor') {
	configurations "asciidoctorExtensions"
	inputs.dir snippetsDir
	dependsOn test
}

...
task copyDocument(type: Copy) {
	dependsOn asciidoctor
	from file("${asciidoctor.outputDir}")
	into file("src/main/resources/static/docs")
}

build {
	dependsOn copyDocument
}

...
bootJar {
	dependsOn copyDocument
	from ("${asciidoctor.outputDir}") {
		into 'static/docs'
	}
}

 

 

애플리케이션 실행 후 웹 브라우저에서 아래 주소로 이동하면 API 문서를 눈으로 확인할 수 있다.

http://localhost:8080/docs/index.html

 

 

 

▶️ API 문서 snippet을 사용하기 위한 템플릿(또는 source 파일) 생성

 

API 문서 스니핏이 생성 되었을 때 이 스니핏을 사용해서 최종 API 문서로 만들어 주는 템플릿 문서(index.adoc)을 생성한다.

 

아래 경로에 해당하는 디렉토리 생성 (Gradle 기반 프로젝트)

src/docs/asciidoc/

 

디렉토리 내에 비어있는 템플릿 문서를 생성 (index.adoc)

 

 

 

 

Controller 테스트 케이스에 Spring Rest Docs 적용하기

 

 

➤ API 문서화를 위한 슬라이스 테스트 케이스 작성

 

Controller 슬라이스 테스트 클래스를 작성하고 API 문서화를 위한 코드를 추가해준다.

 

 

▶️ @SpringBootTest -> @WebMvcTest 로 변경

 

🍎 @WebMvcTest 는 Controller를 테스트 하기 위한 전용 애너테이션이다.

🍎 @WebMvcTest 괄호 안에 테스트 대상 Controller 클래스를 지정해준다.

 

 

▶️ @MockBean(JpaMetamodelMappingContext.class)

 

🍎 JPA에서 사용하는 Bean 들을 Mock 객체로 주입해주는 설정이다.

 

Spring Boot 기반의 테스트는 항상 최상위 패키지 경로에 있는 ~Application 클래스를 찾아서 실행한다.

~Application 클래스에 @EnableJpaAuditing 추가

➡️ JPA와 관련된 Bean을 필요로 하기 때문에 @WebMvcTest 애너테이션을 사용해서 테스트를 진행할 경우 JpaMetamodelMappingContext를 Mock 객체로 주입해주어야 한다.

 

 

▶️ 테스트 클래스 위에 @AutoConfigureRestDocs 추가

 

🍎 Spring Rest Docs 에 대한 자동 구성을 해준다.

 

 

▶️ document(..)

 

🍎 API 문서 자동 생성을 위한 API 스펙 정보 추가

🍎 .anDo(..) 메서드 : andExpect() 처럼 어떤 검증 작업을 하는 것이 아닌 일반적인 동작을 정의하고자 할 때 사용한다.

 

 

▶️ @SpringBootTest vs @WebMvcTest

 

🍓 @SpringBootTest

  • @AutoConfigureMockMvc 와 함께 사용되어 Controller 를 테스트할 수 있다.
  • 프로젝트에서 사용하는 전체 Bean을 ApplicationContext 에 등록하여 사용한다.
  • 테스트 환경을 구성하는 것은 편리하지만 실행속도가 상대적으로 느리다.

 

🍓 @WebMvcTest

  • Controller 테스트에 필요한 Bean만 ApplicationContext에 등록한다.
  • 실행 속도가 상대적으로 빠르다.
  • 하지만 테스트 하려는 클래스에서 의존하고 있는 객체가 있다면 해당 객체에 대해서 Mock 객체를 사용하여 의존성을 일일이 제거해주어야 한다.

 

 

 

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 🤩

 

 

 

반응형
반응형

 

 

 

 

 

Mockito

 

 

➤ Mock이란?

 

mock의 사전적 의미

not real, but intended to be very similar to real situation, substance etc

 

테스트 할 때 Mock의 의미 : 가짜 객체

단위 테스트나 슬라이스 테스트 등에 Mock 객체를 사용하는 것을 Mocking이라고 한다.

 

 

 

➤ 테스트에서 Mock 객체를 사용하는 이유

 

 

▶️ Mock 객체를 사용하지 않고 테스트를 수행할 경우

 

테스트 하고자 하는 계층(클래스)가 다른 계층이나 데이터베이스까지 호출하기 때문에 슬라이스 테스트라고 보기 어렵다.

예를 들어 API 계층을 테스트하기 위해 Controller를 테스트할 때 Mock 객체가 없으면

Controller에 요청을 보내고 Controller는 Service 를 호출하고

Service는 다시 요청에 맞는 메서드를 데이터액세스 계층인 Repository에서 호출할 것이다.

그러면 Repository는 DB에서 해당하는 명령을 수행하고 다시 돌아간다.

이렇게 되면 Controller 뿐 아니라 모든 계층을 원치않게 다 테스트하게 된다.

이러면 테스트에 실패했을 때 어느 부분이 문제인지 제대로 파악하기 어렵다.

 

이런 문제 때문에 Mock 객체가 필요하다.

Mock 객체를 사용하면 Controller를 테스트할 때

Service 객체가 아닌 MockService 객체를 호출하여 더이상 다른 계층을 호출하는 것을 막아준다.

Mock 객체를 사용하면 다른 계층과 단절하여 불필요한 과정을 줄일 수 있게 된다.

 

 

 

➤ Mockito 란?

 

Mock 객체로 Mocking을 할 수 있게 해주는 다양한 오픈 소스 라이브러리가 있다.

Mockito는 그 중에 가장 많이 사용하고 Spring Framework 자체적으로 지원하고 있는 라이브러리이다.

 

Mockito의 Mocking 기능을 이용해서 테스트 하려는 대상 외의 다른 영역을 단절시켜 오로지 테스트 대상에만 집중할 수 있다.

 

 

 

➤ 슬라이스 테스트에 Mockito 적용

 

 

▶️ @MockBean

 

필드에 추가하면 Application Context에 등록되어 있는 Bean에 대한 Mockito Mock 객체를 생성하고 주입(DI)해주는 역할을 한다.

 

 

▶️ Stubbing 메서드

 

Mockito에서 지원하는 메서드 이다.

 

✅ given()

Mock 객체가 특정 값을 리턴하는 동작을 지정하는데 사용한다.

Mockito에서 지원하는 when()과 동일한 기능을 한다.

Mickito.any() 에 매개변수로 실제로 리턴받을 타입을 지정해준다.

 

※ void 타입으로 리턴시에는 doNothing()으로 한번 감싸준다.

ex) doNothing().when(orderService).deleteOrder(anyLong());

 

 

✅ willReturn()

메서드가 리턴할 Stub 데이터이다.

 

 

▶️ Stubbing 이란?

 

테스트를 위해서 Mock 객체가 항상 일정한 동작을 하도록 지정하는 것을 의미한다.

 

 

▶️ @ExtendWith(MockitoExtension.class)

 

Spring을 사용하지 않고, Junit에서 Mockito의 기능을 사용하기위해 test 클래스 이름 위에 추가해준다.

 

 

▶️ @Mock

 

필드에 추가하면 해당 필드의 객체를 Mock 객체로 생성한다.

 

 

▶️ @InjectMocks

 

필드에 추가하면 생성한 Mock 객체를 주입해준다.

 

 

 

 

TDD

 

 

➤ TDD(Test Driven Development) 란?

 

테스트 주도 개발

테스트가 중심으로 하는 개발을 말한다.

테스트 부분을 먼저 만들고 코드 구현은 그 다음에 한다.

 

 

➤ TDD 가 아닌 전통적인 개발 방식

 

TDD 방식이 아닌 방식으로 개발하면 일반적으로 코드를 먼저 작성해서 구현한 후에 테스트를 통해 문제가 있는지 확인한다.

선 구현, 후 테스트

 

 

➤ TDD 방식으로 개발하기

 

메서드 작성 전에 먼저 테스트 클래스 부터 만든다.

존재하지 않는 클래스로 에러가 떠도 일단 테스트를 작성한다.

 

테스트 클래스가 passed 하는 방향으로 코드를 작성한다.

(처음에 클래스가 없어서 나오는 에러도 실행하면 passed 하지 않기 때문에 “failed” 라고 볼 수 있다.)

 

모든 조건에 만족하는 테스트를 먼저 작성 ➡️ 조건에 만족하지 않는 테스트 작성

단계적으로 작성하면서 해결한다.

 

실패하는 테스트 ➡️ 실패하는 테스트를 성공할 만큼의 기능 구현 ➡️ 성공하는 테스트 ➡️ 리팩토링 ➡️ 실패하는 테스트와 성공하는 테스트 확인

 

TDD 개발 방식 모식도

 

 

 

➤ TDD의 장점과 단점

 

 

▶️ 장점

 

  • 테스트를 통과할 만큼만 기능을 구현해서 한번에 너무 많은 기능을 구현할 필요가 없다.
  • 테스트 코드가 추가되면서 검증 범위가 넓어질 수록 기능 구현도 점진적으로 완성된다.
  • 리팩토링 할 부분이 보이면 그때그때 빠르게 진행하기 때문에 리팩토링의 비용이 상대적으로 작아진다.
  • 이미 잘 동작하는 코드를 수정하는 일은 부담스럽지만 TDD 방식은 항상 테스트 케이스가 존재하기 때문에 기존의 코드를 수정해도 상대적으로 심리적 불안감이 줄어든다.
  • 리팩토링을 통해 꾸준히 코드를 개선해서 코드의 품질을 일정 부분 유지할 수 있다.
  • 코드 수정 이후 바로 테스트를 진행할 수 있어서 수정 결과를 빠르게 피드백 받을 수 있다.

 

 

▶️ 단점

 

  • 테스트를 먼저 작성하는 것이 익숙하지 않다.
  • 팀 단위 개발에서 팀원들 간 사전에 협의가 되어야 한다.

 

 

 

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 🤩

 

 

반응형
반응형

 

 

 

 

 

 

토큰 기반 인증

 

 

➤ 토큰기반 인증을 쓰는 이유?

 

 

세션기반 인증 = 서버(혹은 데이터베이스)에 유저 정보를 담는 방식

매번 요청할 때마다 서버(와 데이터베이스)를 살펴봐야하기 때문에 서버의 부담이 크다.

이 부담을 클라이언트에게 넘겨줄 수 없을까 하는 고민에서 Token 인증 방식이 생겨났다.

대표적 토큰 기반 인증 : JWT(JSON Web Token)

 

 

 

➤ 토큰(Token)이 무엇인가?

 

화폐로 사용하는 토큰

오락실

행사에 입장할 때 사용하는 토큰

 

➡️ 돈을 이미 지불했고 이 서비스를 이용할 수 있다는 정보를 담고 있음

 

 

 

 ➤ 토큰을 클라이언트에 저장하는 것은 위험하지 않을까?

 

토큰을 클라이언트가 가지고 있으면 XSS 공격에 노출되는 위험이 있지 않을까?

토큰은 유저정보를 암호화한 상태로 담을 수 있고, 암호화했기 때문에 클라이언트에 담아도 위험하지 않다.

 

 

 

➤ JWT란?

 

토큰 기반 인증 방식은 다양하다.

그 중에서 가장 많이 사용하는 것이 JWT이다.

JSON Web Token의 약자

JSON 포맷으로 사용자에 대한 속성을 저장하는 웹 토큰이다.

토큰 인증 방식중 가장 일반적으로 사용된다.

 

 

 

➤ JWT의 구조

 

 

JWT 예시

 

. 을 기준으로 세 부분으로 나눠진다.

 

1. Header

토큰의 타입(JSON), 어떤 해시 암호화 알고리즘으로 sign할지가 적혀있다.

➡️ JSON 타입을 base64방식으로 인코딩한다.

 

2. Payload

유저의 정보가 담겨있다.

어떤 정보에 접근 가능한지에 대한 권한을 담을 수도 있고, 사용자의 유저 이름 등 필요한 데이터를 담을 수 있다.

민감한 정보가 들어가선 안된다.

➡️ JSON 타입을 base64방식으로 인코딩한다.

 

3. Signature

Header, Payload를 base64 인코딩한 값과 salt값의 조합으로 암호화된 값

Signature에서는 원하는 비밀키(암호화에 추가할 salt)와 Header에서 지정한 알고리즘을 사용하여 암호화한다.

 

base64 인코딩은 누구나 쉽게 디코딩할 수 있지만 비밀키를 사용해 암호화한 값(시그니처)은 비밀키를 보유하고 있는게 아니라면 해독하는게 엄청 어렵다.

 

ex) HMAC SHA256 알고리즘을 사용한 Signature 생성

HMASHA256(base64urlEncode(header) + “.” + base64urlEncode(payload), secret);

 

 

 

 

➤ JWT의 종류

 

JWT는 다음의 두가지 종류의 토큰을 이용해 인증을 구현한다.

클라이언트는 처음 인증을 받게 될 때 두가지의 토큰을 받는다.

 

 

▶️ 액세스 토큰(Access Token)

 

보호된 정보들(유저의 이메일, 연락처 등)에 접근할 수 있는 권한부여에 사용한다.

실제로 권한을 얻는데 사용하는 토큰이다.

 

 

▶️ 리프레시 토큰(Refresh Token)

 

액세스 토큰이 탈취되는 것을 방지하기 위해서 액세스 토큰은 비교적 짧은 유효기간을 가지고 있다.

이때 액세스 토큰의 유효기간이 만료되면 리프레시 토큰을 사용하여 새로운 액세스 토큰을 발급받는다. ➡️ 유저가 다시 로그인할 필요 없음

액세스 토큰에 비해 유효기간이 길다.

리프레시 토큰까지 악의적인 유저가 얻어낸다면 큰 문제가 된다.

그렇기 때문에 유저의 편의보다는 정보를 지키는 것이 더 중요한 웹사이트들은 리프레시 토큰을 사용하지 않는 곳이 많다.

 

 

 

➤ 토큰 기반 인증 절차

 

토큰 기반 인증 절차

 

1. 클라이언트가 서버에 아이디/비밀번호를 담아 로그인 요청을 보낸다.

 

2. 아이디/비밀번호가 일치하는지 확인하고 클라이언트에게 보낼 암호화된 토큰을 생성한다.

액세스 / 리프레시 토큰을 모두 생성한다.

토큰에 담길정보(payload)는 유저를 식별할 정보, 권한이 부여된 카테고리 등이 될 수 있다.

두 종류의 토큰이 같은 정보를 담을 필요는 없다.

 

3. 클라이언트는 토큰을 저장한다.

Local Storage, cookie, Session Storage 등 다양한 공간에 저장 가능

 

4. 클라이언트가 HTTP 헤더(Authorization Header) 또는 쿠키에 토큰을 담아 보낸다.

bearer authentication을 이용한다.

 

5. 서버는 토큰을 해독하여 발급한 토큰과 동일하다고 판단될 경우 클라이언트의 요청을 처리한 후 응답을 보내준다.

 

 

참고) Bearer Token

참고) Bearer Token Details

 

 

 

 

JWT의 장점과 단점

 

 

➤ JWT를 통한 인증의 장점

 

1. Statelessness & Scalability(무상태성 & 확장성)

 

🍒 서버는 클라이언트에 대한 정보를 저장할 필요가 없다. (토큰 해독이 되는지만 판단한다.)

🍒 클라이언트는 요청을 보낼 때마다 토큰을 헤더에 포함시켜서 인증을 한다.

🍒 서버를 여러개 가지고 있는 서비스에서 더 효율적이다. 같은 토큰을 여러 서버에서 인증 가능하기 때문이다. 세션의 경우는 모든 서버가 유저의 정보를 공유하고 있어야 한다.

 

 

2. 안정성

 

🍒 암호화 한 토큰을 사용

🍒 암호화한 키를 노출할 필요가 없음

 

 

3. 어디서나 생산 가능

 

🍒 토큰을 확인하는 서버가 꼭 토큰을 만들지 않아도 됨

🍒 토큰 생성용 서버를 만들거나, 다른 회사에 토큰 생성만 맡기는 등 다양한 활용이 가능하다.

 

 

4. 권한 부여에 용이

 

🍒 토큰의 payload(내용물) 안에 어떤 정보에 접근 가능한지 정의할 수 있다.

 

 

 

➤ JWT를 통한 인증의 단점

 

 

1. Payload를 해독할 수 있음

 

Payload는 base64로 인코딩 되어있기 때문에 토큰을 탈취하여 Payload를 해독하면 데이터를 확인할 수 있다. ➡️ 민감하고 중요한 정보는 Payload에 저장 x

 

 

2. 토큰의 길이가 길어지면 네트워크에 부하를 줄 수 있다.

 

토큰에 저장하는 정보의 양이 길어지면 토큰의 길이가 길어진다. 요청마다 긴 토큰과 함께 전송하면 네트워크에 부하를 줄 수 있다.

 

 

3. 토큰은 자동으로 생성되지 않는다.

 

JWT는 상태를 저장하지 않기 때문에 자동으로 삭제되지 않아서 토큰 유효기간(만료시간)을 반드시 설정해야 한다.

토큰이 탈취되면 기한이 만료될 때까지 대처가 불가능하기 때문에 만료시간을 너무 길게 설정하면 안된다.

 

 

4. 토큰은 어딘가에 저장되어야 한다.

 

토큰은 클라이언트가 가지고 있다가 인증이 필요한 요청을 보낼 때마다 함께 전송할 수 있어야 한다.

 

 

 

 

Spring Security 에서의 JWT 인증

 

 

➤ 프로젝트 사전 준비

 

 

▶️ 의존성 추가

 

  • Spring Boot DevTools
  • Lombok
  • Spring Web
  • Spring Security
  • Spring Data JPA
  • H2 Database

+ JWT 의존성 추가

implementation 'com.auth0:java-jwt:4.0.0'

 

 

▶️ application.yml 설정

 

spring:
  h2:
    console:
      enabled: true
      path: /h2
    datasource:
      url: jdbc:h2:mem:test
    jpa:
      hibernate:
        ddl-auto: create
      show-sql: true

 

 

 

➤ JWT에 필요한 Security 설정

 

 

▶️ 유저 entity에 role 추가

 

유저 entity 필드값에 인가 등급을 저장하기 위한 role 변수 추가

 

 

▶️ SecurityConfig 클래스 생성

 

🍑 JWT를 사용하기 위한 기본 설정들

  • JWT는 headers에 Authorization 값에 토큰을 보내는 방식이다. (-> Bearer)
  • 토큰 정보는 노출되면 안되지만 노출되어도 큰 위험은 없다. (유효시간을 지정했기 때문)

 

 

🍑 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

  • Web은 기본적으로 stateless인데 session이나 cookie를 사용할 수 있다.
  • session / cookie 를 만들지 않고 STATELESS로 진행하겠다는 의미이다.

 

 

🍑 .formLogin().disable()

  • form Login 을 사용하지 않는다.

 

 

🍑 .httpBasic().disable()

  • http 통신을 할 때 headers에 Authorization 값을 ID, Password를 입력하는 방식이다.
  • https를 사용하면 ID와 Password가 암호화되어 전달된다.
  • http 로그인 방식을 사용하지 않는다.

 

 

▶️ CorsConfig 클래스 생성

 

⚠️ 주의) CorsFilter 클래스 import

CorsFilter를 import 해올 때 두가지 경로에 존재하는데 실습데로 구현하려면 아래의 경로에서 import 해와야 한다.

import org.springframework.web.filter.CorsFilter;

 

 

🍈 .setAllowCredentials(true)

  • true : 서버가 응답할 때 json을 자바스크립에서 처리할 수 있게함

 

 

🍈 .addAllowedOrigin(“*”)

  • 모든(*) ip에 응답 허용

 

 

🍈 .addAllowedHeader(“*”)

  • 모든(*) header에 응답 허용

 

 

🍈 .addAllowedMethod(“*”)

  • 모든 http 메서드(post, get, patch, delete) 요청 허용

 

 

 

 

 

JWT Bearer 인증

 

 

➤ Session & Cookie 인증 방식

 

사용자가 로그인 요청을 보내면 사용자를 확인 후 session ID를 발급한다.

발급한 ID를 이용해 다른 요청과 응답을 처리하는 방식이다.

 

 

➤ Token 인증 방식

 

서버에 별도의 저장소가 필요없다.

로그인 시 클라이언트에 토큰을 발급해주고 클라이언트가 요청을 보낼 때마다 발급받은 토큰을 헤더를 통해 전달받아 응답받는 방식이다.

 

 

▶️ 장점

 

🍅 토큰 기반 인증은 쿠키나 세션을 이용한 인증보다 보안성이 강하고 효율적이다.

  • 쿠키 인증은 HTTP 방식 통신을 사용하는 경우 정보가 유출되기 쉽다.
  • 세션 인증은 서버에서 처리해야하기 때문에 추가적인 데이터베이스 공간이 필요하므로 사용자가 점점 많아지면 부담이 될 수 있다.

 

🍅 토큰은 누구나 디코딩하여 데이터가 유출될 수 있어도 Signature 필드가 header와 payload를 통해 만들어져 데이터 변조 후 재전송을 막을 수 있다.

 

🍅 stateless(무상태성) 서버를 만들 수 있다.

  • 서버에 상태를 저장하지 않기 때문이다.

 

🍅 인증정보를 OAuth로 이용할 수 있다.

 

 

일반적으로 토큰은 request header의 Authorization 필드에 담겨져 보내진다.

request header의 Authorization 필드 구조 : Authorization: <type> <credentials>

 

 

 

➤ Bearer 인증 방식

 

JWT or OAuth 토큰을 사용한다.

 

 

➤ Filter 생성

 

Spring Security

 

▶️ addFilterBefore() / addFilterAfter()

 

SecurityFilterChain에 있는 필터 전/후로 필터를 적용해주는 메서드이다.

addFilterBefore(필터, 특정 필터 이름.class)

ex) http.addFilterAfter(new FirstFilter(), BasicAuthenticationFilter.class);

 

 

 

➤ Token 적용

 

▶️ HttpServletRequest

  • ServletRequest를 상속한다.
  • Http 프로토콜의 request 정보를 서블릿에 전달하기 위한 목적으로 사용
  • Header 정보, Parameter, cookie, URI, URL 등의 정보를 읽어들이는 메서드를 가진 클래스
  • Body의 Stream을 읽어들이는 메서드를 가지고 있다.

 

 

▶️ HttpServletResponse

  • ServletResponse를 상속한다.
  • Servlet이 ServletResponse 객체에 Content Type, 응답코드, 응답 메세지 등을 담아서 전송한다.

 

 

 

참고) JWT 공식 사이트

 

 

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 🤩

 

 

 

반응형
반응형

 

 

 

 

 

 

Hamcrest

 

 

 

➤ Hamcrest 란?

 

 

▶️ Hamcrest란?

 

🍉 Hamcrest 는 JUnit 기반의 단위 테스트에서 사용할 수 있는 Assertion Framework 이다.

🍉 JUnit에서 Assertion을 위한 다양한 메서드를 지원한다.

 

 

▶️ Hamcrest를 사용하는 이유

 

🍉 Assertion을 위한 매쳐(Matcher)가 자연스러운 문장으로 이어져서 가독성이 향상된다.

🍉 테스트 실패 메세지를 이해하기 쉽다.

🍉 다양한 Matcher를 제공한다.

 

 

 

➤ JUnit Assertion ➡️ Hamcrest Assertion 적용하기

 

🍇 JUnit Assertion 사용시

public class HelloJUnitTest {
    @DisplayName("Hello JUnit Test")
    @Test
    public void assertionTest() {
        String expected = "Hello, World!";
        String actual = "Hello, JUnit";

        assertEquals(expected, actual);
    }
}

콘솔 출력 결과

expected: <Hello, World!> but was: <Hello, JUnit>
Expected :Hello, World!
Actual   :Hello, JUnit

 

 

🍇 Hamcrest의 Matcher 사용시

public class HelloHamcrestTest {
    @DisplayName("Hello Junit Test using hamcrest")
    @Test
    public void assertionTest1() {
        String expected = "Hello, World!";
        String actual = "Hello, Hamcrest";

        assertThat(actual, is(equalTo(expected)));
    }
}

콘솔 출력 결과

Expected: is "Hello, World!"
     but: was "Hello, Hamcrest"
Expected :Hello, World!
Actual   :Hello, Hamcrest

 

 

▶️ assertThat(actual, is(equalTo(expected)));

 

  • JUnit의 assertEquals(expected, actual) 와 비슷하지만 더 쉽다.

 

 

 

▶️ JUnit의 Assertion vs Hamcrest Assertion 테스트 결과

 

Hamcrest의 Matcher를 사용하면 사람이 읽기 편한 자연스러운 Assertion 문장을 구성할 수 있다. ➡️ 가독성이 많이 높아진다.

테스팅 실패 메시지를 이해하기 더 쉽다.

 

 

더 많은 Hamcrest Matcher

Custom Matcher

 

 

 

 

슬라이스 테스트 (Slice Test)

 

 

➤ 슬라이스 테스트란?

 

각 계층에 구현한 기능들이 잘 동작하는지 특정 계층만 잘라서(Slice) 테스트하는 것

 

 

※ 스모크 테스트(Smoke Test)

소프트웨어의 본격적인 테스트에 앞서, 구축된 테스트 환경에서 테스트가 가능한지를 판단하기 위해 주요 모듈을 간단하게 테스트하는 것이다. 세세한 테스트를 하는 것이 아니라 테스팅 전에 큰 결함은 없는지 확인하는 과정이라고 볼 수 있다.

 

 

➤ API 계층 테스트

 

API 계층 테스트 대상은 대부분 클라이언트의 요청을 받아들이는 핸들러인 Controller 이다.

 

 

▶️ @SpringBootTest

 

Spring Boot 기반의 애플리케이션을 테스트하기 위한 Application Context를 생성한다.

 

 

▶️ @AutoConfigureMockMvc

 

Controller 테스트를 위한 애플리케이션의 자동 구성 작업을 해준다.

MocMvc 기능을 사용하기 위해서는 이 애너테이션을 추가해야 한다.

 

 

▶️ MockMvc

 

Controller 테스트 클래스에 DI 로 주입받은 MockMvc 는 Tomcat 같은 서버를 실행하지 않고 Spring 기반 애플리케이션의 Controller를 테스트할 수 있는 완벽한 환경을 지원해준다.

➡️ Spring MVC 테스트 프레임워크

MockMvc 객체를 통해 Controller를 호출해서 손쉽게 테스트를 진행할 수 있다.

 

 

 

▶️ Given

 

🍊 request body 에 포함시키는 요청 데이터와 동일한 역할을 하게끔 작성한다.

🍊 dto의 테스트하고자 하는 객체를 생성한다.

🍊 Gson(JSON 변환 라이브러리) 을 이용하여 dto 객체를 JSON 포맷으로 변환해준다.

 

 

▶️ When

 

🍊 HTTP request 에 대한 정보를 MockMvcRequestBuilders 클래스를 이용해서 빌더 패턴으로 채워준다.

🍊 MockMvc 객체의 perform() 메서드 호출

🍊 post() 메서드 : HTTP POST 메서드와 request URL을 설정한다. (다른 http 메서드도 가능)

🍊 accept() 메서드 : 클라이언트 쪽에서 리턴 받을 응답 데이터 타입으로 JSON 타입 설정

🍊 contentType() 메서드 : 서버 쪽에서 처리가능한 Content Type으로 JSON 타입 설정

🍊 content() 메서드 : request body 데이터를 설정한다. (Gson을 이용해 변환된 Json 문자열)

🍊 perform() 이 최종적으로 ResultActions 타입을 리턴한다.

 

⚠️ post() 메서드 사용하기 위해 import 해올 때 잘못된 경로의 post를 import하지 않도록 주의한다.

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

 

 

▶️ Then

 

🍊 ResultActions 객체를 이용해서 전송한 request 에 대한 검증을 수행한다.

🍊 andExpect() 메서드 : 파라미터로 입력한 매처(Matcher)로 예상되는 기대 결과를 검증한다.

🍊 status().isCreated() : response status 가 201(Created)가 맞는지 검증한다. (is뒤에 원하는 response status를 넣으면 된다.)

🍊 andReturn() : 디버깅 용도로 response로 전달되는 응답 데이터를 출력할 때 사용한다.

🍊 jsonPath() : response body의 각 property 중에서 응답으로 전달 받는 특정 값이 response body로 전송한 값과 동일한지 검증할 수 있다. jsonPath()를 사용하면 JSON 형식의 개별 property에 손쉽게 접근할 수 있다.

 

심화학습) jsonPath()

 

 

Member Cotroller의 getMember 테스트 예시 코드

@Test
void getMemberTest() throws Exception {
        // given
        long memberId = member1.getMemberId();
        Member member = repository.findById(memberId).get();
        String content = gson.toJson(String.valueOf(memberId));

        // when
        ResultActions actions =
                mockMvc.perform(
                        get("/v11/members/" + memberId)
                                .accept(MediaType.APPLICATION_JSON)
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(content)
                );

        // then
        MvcResult result = actions
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.email").value(member.getEmail()))
                .andExpect(jsonPath("$.data.name").value(member.getName()))
                .andExpect(jsonPath("$.data.phone").value(member.getPhone()))
                .andReturn();
}

 

 

 

✔️ response body 응답 데이터에 한글이 깨질 경우

 

resources 패키지 안에 application.yml에 들어가서 아래의 코드를 추가한다.

server:
  servlet:
    encoding:
      force-response: true

 

 

 

 

➤ 데이터 액세스 계층 테스트

 

 

데이터 액세스 계층 테스트를 위해 테스트하려는 repository를 DI 로 주입한다.

 

 

▶️ @DataJpaTest

 

🥭 Repository 기능을 정상적으로 사용하기 위해 Configuration을 Spring이 자동으로 해주게 된다.

🥭 @Transactional 애너테이션을 포함하고 있기 때문에 하나의 테스트 케이스 실행이 종료되는 시점에 데이터베이스에 저장된 데이터는 rollback 된다.

🥭 여러 개의 테스트 케이스를 한꺼번에 실행시켜도 하나의 테스트 케이스가 종료될 때마다 데이터 베이스의 상태가 초기 상태를 유지한다.

 

참고) @DataJpaTest 애너테이션 doc

 

 

▶️ Repository DI로 주입

 

@Autowired
private MemberRepository memberRepository;

 

 

▶️ Given

 

테스트 할 Entity 정보를 준비한다.

 

 

▶️ when

 

정보를 테스트하고자 하는 메서드를 불러서 테스트한다.

 

 

▶️ Then

 

정보가 잘 저장되었는지 검증(assertion) 한다.

 

 

 

 

테스팅 유닛 예제 코드(깃허브)

 

 

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 🤩

 

 

반응형
반응형

 

 

 

 

Cloud Service 대표 예시

 

 

 

만든 웹 서비스를 배포하지 않는다면... 더 이상 의미를 가질 수 없다.

따라서 웹 개발자라면 배포에 대한 기본 지식을 탑재하고 있고 혼자서 간단한 배포정도는 할 줄 알아야 한다.!

 

요즘엔 서버실을 직접 구축하기 보다 비용, 시간 면에서 유리한 배포를 위한 클라우드 서비스를 이용한다.

가장 일반적으로 사용하는 클라우드 서비스는 Amazon Web Service(AWS) 이다.

많은 국내외 기업에서 배포를 위해 AWS를 사용하기 때문에 취업시장에서 AWS를 잘 다룰 수록 유리하다.

 

AWS 배포를 배우려면..

  1. 3 Tier Architecture 구성을 이해하고 있어야 한다.
  2. Linux 운영체제에서 개발 환경을 처음부터 구축할 수 있어야 한다.

 

 

 

AWS

 

 

✓ 클라우드 서비스 업체의 장점

 

  • 신속한 인프라 구축
  • 유연한 인프라 관리
  • 예상치 못한 트래픽 폭주 대응
  • 손쉬운 글로벌 서비스
  • 강력한 보안과 장애 없는 서비스
  • 합리적인 요금제

 

 

이제 클라우드를 통해 클릭 몇번, 또는 코드 몇줄로 거대한 서버실에 해당하는 네트워크를 구축할 수 있게 되었다. 

자체 서버실을 유지, 운영, 구축하기 위한 초기비용이 들었다면 클라우드 서비스를 이용하는 지금은 사용한 만큼만 비용을 지불하는 온디맨드(On-Demand) 방식의 요금제가 도입되어 보다 합리적으로 서비스 운영이 가능하게 되었다.

 

 

 

 

Cloud Computing

 

 

➤ 클라우드 등장 이전

 

기존 서버의 방식은 서버실(전산실)에 여러대의 서버 컴퓨터를 배치해서 직접 관리했다.
➡️ On-premise(온프레미스) 방식

그런데 만약 서버에 요청수가 늘어나 수용 능력이 한계에 도달하게 되면 어떻게 했을까?

직접 컴퓨터의 개수를 늘리거나 컴퓨터 성능을 업그레이드 했다.

 

기존 방식의 한계

주기적인 유지 관리가 필요하다.

공간의 한계가 있다.

 

그래서 일부 기업에서는 데이터 센터라는 건물을 세우기 시작했다.

이때부터 데이터 센터의 유휴(사용 x)자원을 대여하는 서비스가 등장했다.

 

 

➤ Cloud 등장

 

물리적인 컴퓨터가 아닌 가상 컴퓨터를 대여한다.

가상화(Vitualization)기술의 발전으로 가상 컴퓨터를 제공한다.

 

 

 

▶️ Cloud의 장점

 

🍎 서버의 자원과 공간, 네트워크 환경을 제공한다.

🍎 필요할 때마다 컴퓨팅 능력을 유연하게 조절 가능하다.

🍎 사용한 만큼의 요금만 지급하면 된다.

🍎 다른 컴퓨터로 즉시 이주(migration)가 가능하다.

 

 

▶️ Cloud의 단점

 

클라우드 서비스에 종속되어 클라우드 서비스에 문제가 생기면 내 서비스에도 영향을 미친다.

 

 

➤ Cloud 서비스 형태

 

 

출처: RedHat https://www.redhat.com/ko/topics/cloud-computing/iaas-vs-paas-vs-saas

 

▶️ IaaS(Infrastructure-as-a-Service, 서비스로서의 인프라)

 

  • 종량제 서비스
  • 제공업체에서 storage 관리와 액세스, vitualization, 서버, 네트워크 등 인프라 서비스를 클라우드로 제공
  • 장점 : 개발 및 테스트 환경의 구축 및 제거가 빠르고 유연하다.
  • 단점 : 제공업체의 보안 문제 가능성, 제공업체가 여러 클라이언트와 인프라 리소스를 공유해야 하는 멀티 테넌시(Multitenancy) 시스템 및 서비스 신뢰성
  • 예시 : AWS, Microsoft Azure, Google Cloud

 

✅ Multitenancy(멀티 태넌시) : 단일 소프트웨어 인스턴스로 서로 다른 여러 사용자 그룹에 서비스를 제공할 수 있는 소프트웨어 아키텍처

 

 

▶️ PaaS(Platform-as-a-Service, 서비스로서의 플랫폼)

 

  • 제공업체가 자체 인프라에서 하드웨어와 소프트웨어를 호스팅한다.
  • 호스팅한 플랫폼을 사용자에게 통합 솔루션, 솔루션 스택 또는 인터넷을 통한 서비스로 제공한다.
  • 인프라나 플랫폼 구축, 유지관리할 필요 없이 사용자가 자체 애플리케이션을 관리, 실행하는데 집중할 수 있게 해준다.
  • 빌드 및 배포를 위한 환경이 사용자에게 제공된다.
  • 예시 : AWS Elastic Beanstalk, Heroku, Red Hat OpenShift

 

 

▶️ SaaS(Software-as-a-Service, 서비스로서의 소프트웨어)

 

  • 가장 포괄적인 형식의 클라우드 컴퓨팅 서비스
  • 모든 애플리케이션은 제공업체가 관리하며 웹 브라우저를 통해 제공한다.
  • 제공업체가 소프트웨어의 전반적인 관리 작업을 처리하며, 사용자는 대시보드 또는 API를 통해 애플리케이션에 연결한다.
  • 장점 : 시간과 유지관리를 훨씬 줄일 수 있다.
  • 단점 : 제어, 보안 및 성능과 관련된 비용이 소요 ➡️ 신뢰할 수 있는 제공업체 선정이 중요
  • 예시 : Dropbox, Salesforce, Google Apps

 

 

※ 미들웨어(Middleware)란?

 

미들웨어는 서로 다른 애플리케이션간의 통신에 사용되는 소프트웨어를 말한다.

주로 컴퓨터 제작회사가 운영체제와 응용 소프트웨어의 중간에서 조정과 중개의 역할을 수행하도록 만든 소프트웨어이다.

데이터관리, 애플리케이션 서비스, 메시징, 인증 및 API 관리를 주로 처리한다.

클라우드 컴퓨팅에서 미들웨어는 고도로 분산된 플랫폼 전반에서 원활하고 일관되게 작동하는 애플리케이션 환경을 지원한다.

 

참고) RedHat 홈페이지 IaaS, PaaS, SaaS 비교글

 

 

 

Deploy

 

 

➤ Deployment

 

전개, 배포라는 의미이다.

배포란 개발한 서비스를 이용자가 이용가능하게 하는 과정이다.

 

개발부터 배포까지는 보통 크게 4단계로 이루어져 있다.

Development ➡️ Integration ➡️ Staging ➡️ Production

 

 

▶️ Development

 

🥝 Local 컴퓨터 환경에서 개발 및 테스트

🥝 더미 데이터를 이용한 테스트

🥝 변경 사항이 있어도 문제가 되지 않음

🥝 모든 구성원이 각자의 환경에서 진행

 

 

▶️ Integration

 

🥝 각자의 환경에서 개발된 부분을 취합

🥝 코드간 Conflict가 없는지 확인하는 단계

🥝 작성한 코드가 다른 코드에 문제를 발생시키지 않는지 확인

 

 

▶️ Staging

 

🥝 Production 단계와 가장 유사한 환경에서 테스트

🥝 실제 데이터를 복사해서 테스트에 사용

🥝 모든 관계자들에게 검증하는 단계

 

 

▶️ Production

 

  • 개발환경과는 구분된 환경
  • 실제 데이터를 이용
  • 실제로 서비스가 제공되는 단계

 

 

✅ 배포에서는 환경의 차이를 이해하고 환경설정을 코드와 분리하는 것이 중요하다.

 

 

➤ 작성한 코드가 다른 환경에서도 정상 작동할 수 있게 하려면?

 

🍅 절대경로 대신 상대경로를 사용한다.

🍅 환경에 따라 포트를 분기할 수 있도록 환경변수를 설정한다.

🍅 Docker와 같은 가상화도구를 이용해 개발 환경 자체를 통일시킨다.

 

 

 

 

 

EC2

 

 

 

➤ EC2 란?

 

 

Elastic Compute Cloud

 

AWS에서 제공하는 클라우드 컴퓨팅 서비스

AWS에서 원격으로 제어할 수 있는 가상의 컴퓨터를 한대 빌리는 것

 

 

Elastic = 탄력(신축성) 있는, 유연한

➡️ 비용 뿐 아니라 성능, 용량을 자유롭게 조절 가능

 

 

➤ EC2 의 장점

 

🥑 구성하는데 필요한 시간이 짧다.

🥑 AMI를 통해 다양한 운영체제 선택이 가능하다. (+ CPU, RAM, 용량까지도 손쉽게 구성 가능)

 

 

➤ 인스턴스

 

AWS에서 빌리는 컴퓨터를 Instance라 한다.

인스턴스는 1대의 컴퓨터를 의미하는 단위이다.

AWS에서 컴퓨터를 빌리는 것을 인스턴스를 생성한다고 한다.

 

 

 

➤ AMI(Amazon Machine Image)

 

AMI는 인스턴스를 시작하는데 필요한 소프트웨어 구성이 기재된 템플릿(이미지)이다.

인스턴스를 시작할 때 AMI를 지정해야 한다.

동일한 구성의 인스턴스가 여러개 필요할 땐 한 AMI에서 여러 인스턴스를 시작할 수 있다.

이미지 종류로는 OS만 깔려있는 템플릿을 선택할 수도 있고, 아예 특정 런타임이 설치되어 있는 템플릿이 제공되는 경우도 있다.

ex) 우분투 + node.js, 윈도우 + JVM 등

 

 

참고) aws AMI

 

 

 

✅ AWS EC2 인스턴스를 생성한다

= AMI를 토대로 운영체제, CPU, RAM 혹은 런타임 등이 구성된 컴퓨터를 빌리는 것

 

 

 

 

 

RDS(Relational Database Service)

 

 

AWS에서 제공하는 관계형 데이터베이스 서비스이다.

 

 

 

➤ EC2 인스턴스에 DB 엔진을 설치해서 사용하는 것과 무엇이 다른가?

 

 

EC2 인스턴스를 사용하면 데이터베이스와 관련해서 자동으로 관리하는 부분이 매우 적다.

사용자가 일일이 시간을 투자하여 데이터베이스 엔진의 설치와 버전관리, 데이터 백업을 해야한다.

 

거기다 가용성과 내구성이 확보되지 않기 때문에 데이터가 유실되거나 정상적으로 사용하지 못할 확률이 커진다.

또 후에 필요에 따른 데이터베이스 규모 확장도 어렵다.

 

가용성 : 시스템이 정상적으로 사용가능한 정도

 

RDS를 이용하면 데이터베이스와 관련된 유지 보수를 모두 RDS에서 전적으로 자동 관리한다.

사용자가 해야할 일은 초기 설정을 제외하고는 DB에 저장된 데이터를 관리하는 일밖에 없어서 편의성이 매우 향상된다.

 

 

▶️ RDS를 사용할 경우 AWS에서 관리하는 것들

 

🍅 데이터베이스 규모 확장

🍅 가용성, 내구성 확보

🍅 데이터 백업

🍅 데이터베이스 설치/ 관리

🍅 운영체제 설치/ 관리

🍅 기반 시설 구축

 

RDS에서는 다양한 데이터베이스 엔진 선택지를 제공하기 때문에 실무에서 필요에 맞게 엔진을 취사선택해서 이용할 수 있다.

 

 

 

 

S3

 

 

➤ S3(Simple Storage Service)란?

 

 

▶️ Cloud Storage 란?

 

인터넷 공간에 데이터를 저장하는 저장소이다.

컴퓨터의 하드디스크의 역할을 하는 서비스이다.

ex) Google Drive, 네이버 MYBOX, MS Onedrive

 

클라우드 스토리지는 뛰어난 접근성을 장점으로한다.

 

S3는 AWS에서 제공하는 클라우드 스토리지 서비스이다.

 

 

 

➤ S3의 이점

 

 

▶️ 높은 확장성

 

데이터를 무한히 저장 가능하다.

사용한 만큼만 비용을 지불하면 되기 때문에 비용적인 측면에서 매우 효율적

 

 

▶️ 강력한 내구성

 

99.999999999%의 내구성을 보장

S3에 저장한 데이터가 유실될 가능성은 거의 없다.

(벼락맞을 확률이 700배는 더 높다고 한다...😅)

 

 

▶️ 높은 가용성 보장

 

스토리지에 저장된 파일들을 정상적으로 사용할 수 있는 시간이 길다.

99.99%의 스토리지 가용성을 보장한다.

(1년 동안 S3에 파일 저장시, 8.76 시간 동안만 스토리지 사용에 장애가 발생하는 정도라고 한다.)

 

 

※ aws가 높은 가용성과 높은 내구성을 가진 이유

aws는 전세계 곳곳에 격리된 리전(Region)이라는 것을 세워놓았다.

이 리전을 통해 EC2를 세계 각지의 여러 곳에서 물리적인 서버로 호스팅한다.

가용 영역(Availability Zon)이란 각 리전안에 존재하는 데이터센터(IDC)를 뜻한다.

가용 영역은 각각 개별적인 위치에 떨어져서 존재하기 때문에 한 곳의 가용 영역이 재난이나 사고로 가동이 불가능해지더라도

다른 가용 영역에 백업을 해놓은 데이터를 활용하여 문제없이 서버가 가동되게 된다.

이러한 방식 덕분에 aws가 높은 가용성과 내구성을 보장하는 것이다.

 

참고) EC2 Region

 

 

▶️ 다양한 스토리지 클래스 제공

 

저장소를 어떤 목적으로 활용할지에 따라 효율적으로 선택할 수 있는 스토리지 클래스가 달라진다.

대표적으로 많이 사용하는 스토리지 클래스 : Standard class, Glacier class

 

Standard Class

🍑 범용적인 목적으로 사용하기 좋다.

🍑 데이터 액세스 요청에 대한 처리 속도가 빠르다.

🍑 데이터에 자주 액세스해야 할 경우 사용

🍑 오래보관하는 목적으로는 알맞지 않다. ➡️ 보관비용이 높게 발생!

 

 

Glacier Class

🍑 장기적인 보관 목적으로 적합

🍑 데이터 액세스 속도는 느리다.

🍑 대신 데이터 보관 비용이 매우 저렴하다.

 

 

▶️ 정적 웹 사이트 호스팅이 가능

 

정적 파일: 서버의 개입 없이 생성된 파일(↔️ 동적파일: 클라이언트가 서버에 요청을 보내서 생성한 파일)

 

🍅 웹 호스팅(Web Hosting) : 서버의 한 공간을 임대해 주는 서비스를 뜻한다.

 

S3에서는 버킷이 사용자들이 정적 웹 사이트를 배포할 수 있는 공간을 제공한다.

버킷이라는 저장공간에 정적 파일을 업로드하고 버킷을 정적 웹 사이트 호스팅 용도로 구성하면 정적 웹 사이트를 배포할 수 있다.

 

버킷?

🍅 파일을 담는 바구니(최상위 디렉토리)

🍅 무한히 많은 파일 저장 가능

🍅  버킷의 이름은 각 리전(Region)에서 고유해야 함

🍅  버킷의 정책을 생성하여 액세스 권한을 부여 가능

 

객체?

🍅 버킷에 담기는 파일

🍅 객체는 파일과 메타데이터로 구성

🍅 file(파일): key-value 페어 형식으로 데이터를 저장한다. 실제 데이터를 저장한다.

🍅 key : 각각의 객체를 고유하게 만들어주는 식별자 역할

🍅 메타데이터: 객체의 정보(생성일, 크기, 유형 등)가 담긴 데이터

🍅 객체의 값으로써 저장될 수 있는 데이터 최대 크기는 5TB이다.

🍅 모든 객체는 고유한 키를 가진다.

🍅 모든 객체는 URL 주소를 가지고 있다.

🍅 URL 주소 형식: http://[버킷 이름].S3.amazonaws.com/[객체의 키]

 

 

 

 

 

3-Tier Architecture 배포 전략

 

 

➤ Client 배포

 

AWS에서 제공하는 S3 를 통해 사용자들에게 Client를 제공할 수 있다.

 

클라이언트를 정적 파일로 빌드하여 배포한다.

 

이때 빌드하는 과정이 필요하다.

 

▶️ 여기서의 빌드란?

 

🍋 불필요한 데이터를 없애고, 통합/압축하여 배포하기 최적화된 상태로 만드는 것

🍋 데이터의 용량이 줄어들고 웹 사이트 로딩 속도가 빨라진다.

🍋 HTML, CSS, JS 같은 웹 앱으로 배포하는 경우엔 배포 가능한 정적 파일의 형태로 만들어 주어야 한다.

🍋 asset 자체가 정적인 경우 그대로 배포하면 된다.

 

 

▶️ 사용자들이 더 빠르게 파일을 받게 하는 방법?

 

AWS에서 제공하는 CDN 서비스인 CloudFront를 통해서 각지의 데이터센터에 데이터를 분산시켜서 저장해 뒀다가 사용자와 가까운 지역에서 데이터를 주는 방식으로 더 빠르게 서비스를 제공할 수 있다.

 

※ 참고) CDN(콘텐츠 전송 네트워크)에 대한 설명

 

 

 

➤ Server Application 배포

 

AWS EC2 서비스를 통해 손쉽게 서버를 구성하고 제공할 수 있다.

 

 

 

➤ Database 배포

 

RDS 서비스를 통해 EC2를 통해 배포된 Server Application의 데이터를 저장, 제공하는 데이터베이스를 배포할 수 있다.

 

 

➤ DNS

 

기본으로 생성되는 IP주소는 사용자에게 불편하다.

IP 주소가 아닌 도메인 주소로 사이트에 접근할 수 있다.

AWS에서 제공하는 Route 53 서비스를 이용하면 직관적인 도메인 주소를 통해서 서비스에 접근하도록 할 수 있다.

 

 

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 🤩

 

 

반응형
1 2 3 4 ··· 7