⁉️ 만약 Get"https://127.0.0.1:8200/v1/sys/internal/ui/mounts/secret/application/db": http: server gave HTTP response to HTTPS client이러한 에러가 발생하였을 경우 ↓↓ 아래내용 실행 (터미널)
$ export VAULT_ADDR='http://localhost:8200'
2. key/vaule 생성 및 확인
$ vault kv put secret/application username=mungmang password=12345 # key, vaule 생성
Key Value
--- -----
created_time 2022-01-08T15:46:25.89734Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
$ vault kv get secret/application # path 으로 key, vaule 조회
======= Metadata =======
Key Value
--- -----
created_time 2022-01-08T15:46:25.89734Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
password 12345
username mungmang
// build.gradle 파일에 아래의 정보 추가
ext {
...
set('springCloudVersion', "2021.0.1-SNAPSHOT")
}
dependencies {
...
implementation 'org.springframework.cloud:spring-cloud-starter-vault-config'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
// application.yml에 아래의 내용 추가
spring:
config:
import: vault://
cloud:
vault:
uri: http://localhost:8200
token: 00000000-0000-0000-0000-000000000000
kv:
backend: secret
default-context: application #secret 이후의 경로
✱ 참고로 Spring Cloude Vault 3.0 및 Spring Boot 2.4 이상에선 bootstrap.yml, bootstrap.properties 가 더이상 사용되지 않는다고함. 그리고 Spring Boot Config Data 접근방식을 사용하려면 spring: config: import에 Vault 시스템을 바인딩 하기 위한 속성 설정이 필요함. (Spring Boot 의 Config Data API) 아님, application.yml에 spring:cloud:bootstrap:enabled: true or pom.xml or build.gradle 파일에 spring-cloud-starter-bootstrap import을 하여 bootstrap.yml 을 활성화를 할 수 있음.
// config 패키지 생성후 아래의 클래스 생성
@Getter
@Configuration
public class VaultData {
@Value("${username}")
private String username;
@Value("${password}")
private String password;
}
// 확인
@Slf4j
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(HelloApplication.class, args);
// vault 테스트 --
VaultData vaultData = context.getBean(VaultData.class);
log.info("username:{}", vaultData.getUsername());
log.info("password:{}", vaultData.getPassword());
}
}
‣ 포트 앤 어댑터 아키텍처을 이용 ‣외부영역 & 내부영역 을 나눠 고수준의 내부 영역이 외부 영역에 의존하지 않도록 하는것이다! ‣ 유지보수, 유연성, 확장성에 좋음. ‣ 복잡할수록 빛을 발하지만, 단순하다면 경우 이렇게까지 구성할 필요는 없음!
🔸 외부영역 • 비지니스 처리 결과 리턴 (REST API 발행) • 인바운드 어댑터, 아웃바운드 어댑터로 구성
🔸 내부영역 • 순수 비지니스 로직 구성 • 외부영역과 연계되는 포트를 가지고 있음 • 인바운드 포트, 아웃바운드 포트로 구성 • POJO 존재
‣아웃바운드 어댑터가 아웃바운드 포트에 의존해서 구현됨 ‣어플리케이션이나 어댑터가 변경 되어도 도메인은 영향을 받지않음 ‣클린 아키텍처와도 유사 ‣ SOLID의 단일책임원칙(Single Reason to Change Principle, SRP), 의존성역전원칙(Dependency Inversion Principle, DIP) 을 이용
※ 포트 앤 어댑터 아키텍처 인터페이스나 기반 요소의 변경에 영향을 받지 않는 핵심 코드를 만들고 이를 견고하게 관리하는것이 목표 외부영역과 내부영역을 분리함 영역의 사이 input, ouput 전달은 포트(=인터페이스) 을 통해서만 함.
※ 단일책임원칙(Single Reason to Change Principle, SRP) 하나의 컴포넌트는 오로지 한 가지 일만 해야하고, 그것을 올바르게 수행해야함! = 컴포넌트 변경 이유는 오직 하나뿐이여야함!!!
※ 의존성역전원칙(Dependency Inversion Principle, DIP) 코드상의 어떤 의존성이든 그 방향을 바꿀 수 있다.
🌱인바운드 어댑터 ▪︎ 외부요청 처리 (API 요청/응답 결과) ▪︎ 아웃바운드 포트 인터페이스를 가져다가 사용하여 어댑터를 생성. ▪︎ 스프링 MVC 컨트롤러, 커맨드 핸들러, 이벤트 메세지 구독 핸들러 등.
🌱아웃바운드 어댑터 ▪︎ 내부 비지니스 영역과 외부 서비스간 데이터 교환 ▪︎ 데이터 엑세스 처리 (DAO), 이벤트 메세지 발생, 외부 서비스 호출 등
이를 사용하계된 계기 (계층형 아키텍처의 단점)
‣ 계층형 아키텍처는 데이터베이스 주도 설계를 유도함. (도메인에 의존이 아닌 데이터베이스에 의존) - 비지니스 관점으로는 별로임 ‣ ORM 프레임워크의 경우 계층형 아키텍처와 결합하면 비즈니스 규칙을 영속성 관점과 섞고 싶은 유혹을 쉽게 받음. ‣ 영속성 코드가 도메인코드에 녹아들면 마음대로 바꾸기가 쉽지 않게 됨. ‣ 웹 계층 테스트시 도메인 및 영속성 범위까지 모킹해야함. 시간소요가 많아짐. ‣ 그외에도 테스트가 어렵고 동시작업이 어려움. ‣ 유지보수 쉬운! 소프트웨어를 만들필요성이 있다.
var token = eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0IiwiYXV0aCI6IlJPTEVfVVNFUiIsImV4cCI6MTY0MDI2NjczOX0.A5bzyF4jkKVmdDzboK8_qsPbDh3qGO3v2lgcSp5K41CxmSgyDZlKxBfcZNiZ754S_IDhFOPO7m18bsBqhZgBMw
각 구성 설명은 아래와 같다.
HEADER
signiture 정보를 해싱하기 위한 알고리즘 정보들이 담겨있는곳. HMAC, SHA256 or RSA 와 같은 서명 알고리즘 두 부분으로 구성됨.
PAYLOAD
서버, 클라이언트가 주고 받는 시스템에서 실제로 사용될 정보에 대한 내용이 담겨있음. PAYLOAD claims 은 3가지 유형이 존재
- registered claims: 필수는 아니지만 상호 운용을 위해 미리 정의된 클레임(RFC 7519) 집합 (iss, exp, sub, aud..)
- public claims: jwt 을 사용하는 사람들이 마음대로 정의. 충돌 방지 위해 네임스페이스를 포함하는 URL로 정의 필요
- private claims: 사용에 동의하고 등록된 클레임이나 공개 클레임이 아닌 당사자간의 정보를 공유하기 위해 생성된 맞춤 클레임
SIGNITURE
토큰의 유효성 검증을 위한 문자열. 이 문자열로 유효한 토큰인지 확인함. 메세지가 변경되었는지 확인하는데 사용.
동작방식
jwt 토큰 인증 방식 기준으로 그려본것이다. (oauth2의 허가는 생략)
장점과 단점
장점 중앙의 인증서버, 데이터 스토어에 대한 의존성이 없고, 시스템 수평확장에 유리하다.
단점 PAYLOAD 정보가 많아지면 네트워크 사용량이 증가함. 토큰이 클라이언트에 저장되기에 서버에서 클라이언트의 토큰을 조작할 수 있다.
자원을 표현(Representational)으로 구분하여 해당 자원의 상태(State)를 주고 받는(Transfer)다. HTTP URI(Uniform Resource Identifier)을 통해 자원(Resource)을 명시하고, Http Method(GET, POST, PUT, DELETE)을 통해 자원에 대한 CRUD Operation을 적용
✱ URI (Uniform Resource Identifier) 인터넷 자원을 나타내는 유일한 주소 scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment] - URN: 자원의 이름 (식별자) - URL: 자원의 위치
구성요소
1. 자원 (Resource) ‣ Http URI (ex. /users/:userId)
2. 행위 (Method) ‣ GET, POST, PUT, DELETE, ‣ HEAD (요청 header 정보만 응답), ‣ PATCH (PUT과 다르고, 자원의 일부만 수정하고자 할때 사용), ‣ OPTION (현재 End-point가 제공 가능한 API method를 응답)
3. 표현 (Representation of Resource) Client(브라우저)가 자원의 상태에 대한 조작을 요청(Request)하면 서버는 이에 적절한 응답(Response)을 보낸다. JSON, XML, TEXT, RSS 등 여러 형태로 표현
REST API 특징
1. 클라이언트/서버 ‣아키텍처를 단순화 시키고 작은단위로 분리함으로써 클라이언트 - 서버 각 파트가 독립적으로 개선될 수 있도록 한다.
2. 상태없음 ‣클라이언트의 상태가 서버에 저장되어서는 안된다.
3. 레이어드 아키텍처 (Layered Architecture) ‣클라이언트 - 서버 연결 사이의 중간 서버가 존재하는 경우 (클라이언트 - 중간서버 - 서버), 중간서버(게이트웨이, 방화벽, 프록시 etc)는 로드밸런싱 혹은 공유 캐시 기능을 제공함으로써 시스템 규모 확장성을 향상시키는데 유용
4. 캐시 (Cache) ‣클라이언트 응답을 캐싱할 수 있어야 함. 캐싱함으로서 서버에 부하 최소화
5. 코드 온 디맨드(Code on demand) ‣요청이 오면 코드를 준다는 의미로 특정 시점에 서버가 특정 기능을 수행하는 스크립트 또는 플러그인을 클라이언트에 전달해서 해당 기능을 동작하도록 하는것. (자바스크립트, 플래시 etc)
6. 통합 인터페이스 ‣일관적인 인터페이스로 분리 되어야 함.
REST 인터페이스 규칙
1. 리소스 식별 ‣요청 내에 기술된 개별 자원을 식별할 수 있어야 한다. (URI)
2. 표현을 통한 리소스 처리 ‣다양한 콘텐츠 유형으로 표현 가능 (JSON, XML, HTML ..)
3. 자기 묘사 메세지 ‣Http header 에 메타 데이터 정보를 추가해서 실제 데이터와는 관련 없지만 데이터에 대한 설명을 나타내는 정보를 담을 수 있음.
4. 어플리케이션의 상태에 대한 하이퍼미디어(HATEOAS, Hypermedia As The Engine Of Application State) ‣REST API 개발할 때에 단순 데이터만 전달하지 않고, 링크 정보까지 포함하여 전달 (하이퍼 텍스트 링크) ‣리소스 상태가 전이되는 경우에 변경되는 정보를 제공하고자 함. (등록 요청 후, 변경 된 정보를 좀 더 자세히 알고자 할때 하이퍼 링크도 같이 제공)