$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
3: eno2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
5: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff

작업의 시작은 운용한지 3년이 다되가는 서버들을 점검하는 차원에서 Reboot 겸 update를 하려했다.

 

Dell 서버는 iDRAC(Integrated Dell Remote Access Controller)이란 웹 콘솔을 제공해주어서 직접 Data Center에 가지 않아도 이런작업은 웹 브라우저에서 실행할 수 있다. 웹 브라우저로 접속은 할 수 있지만 물리서버의 Management 전용 IP로 붙어야 한다. 예를 들면 https://172.21.239.47 과 같은 형태의 주소로 접속하고 ID/PW를 입력하여 로그인 하면 서버의 상태 확인 및 remote로 직접 제어할 수 있다.

 

서버의 전원을 켤 때는 높은 전압과 과부하가 생기기때문에 3년이 다되어가는 서버를 껐다가 다시 부팅을 시도하는 경우

다양한 원인으로 서버가 켜지지 않을 수 있다. 그래서 Warm Boot 방식으로 진행했다.

 

사용한지 3년이 다 되어가는(실제로는 2년 10개월) 서버들중 1대에서 Reboot을 완료하고

서버 상태를 확인하는데 네트워크 인터페이스가 Down 상태로 내려가 있어서 통신이 되지 않았다.

서버가 이상한건지 이 앞단에 연결된 스위치가 문제인지 알 수 없었다.

$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
3: eno2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
5: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff

 

네트워크 엔지니어의 확인 결과 LACP(Link Aggregation Control Protocol) PDU(Protocol Data Units)를 받지 못하고 있는 상황이었다.

확인 시에는 스위치장비에 ssh로 접근해서 show interface 를 이용하여 확인한 결과중에 suspended due to no lacp pdus 메시지를 보고 판단하였다.

 

리눅스 서버에서 확인해보면 세팅은 정상이었다.

$ cat /proc/net/bonding/bond0 
Ethernet Channel Bonding Driver: vX.X.X

Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer2 (0)

 

LACP가 문제인가 싶어서 network bonding의 모드를 변경해보았다.

(변경한 후에 실제 반영하려면 `systemctl restart network` 로 서비스를 재시작해주어야 한다.)

$ cat /etc/sysconfig/network-scripts/ifcfg-bond0

NAME=bond0
DEVICE=bond0
ONBOOT=yes
BOOTPROTO=none
IPADDR=172.21.239.209
PREFIX=24
GATEWAY=172.21.239.1
TYPE=Bond
BONDING_OPTS="miimon=100 mode=1"
# 주석처리 BONDING_OPTS="miimon=100 mode=802.3ad"

모드는

 

  • mode=0 혹은 balance-rr
  • mode=1 혹은 active-backup
  • mode=2 혹은 balance-xor
  • mode=3 혹은 broadcast
  • mode=4 혹은 802.3ad

 

자세한 설명은 linux 서버에서 /usr/share/doc/iputils-xxxx/README.bonding 에서 확인할 수 있다.

 

일단 확인해보니 bonding 이슈는 아니었고 다시 설정을 802.3ad로 원복 시켰다.

결국 시스템엔지니어는 데이터센터에 직접 찾아가서 서버를 shutdown 시키고 power cycle 작업을 수행하였다.

약간의 전기가 iDRAC, NIC케이블에 남아있어도 초기화가 안될 수도 있기떄문에 Cold boot를 진행하였다.

이를 위해서 shutdown한 후, 전원케이블을 서버에서 분리하고 네트워크 케이블들도 분리하였다.

 

이러한 작업을 하는김에 NIC의 펌웨어를 업데이트하는 작업을 하였다.

이 작업에서 Dell 서버는 2가지 방식으로 작업이 가능한데

  • DSU (Dell System Update)
  • OME (OpenManage Enterprise)

DSU를 이용하였다.

### 거의 3년만이라 dsu 한번 업데이트 해주고
$ yum update dell-system-update -y

### 업데이트 할때 파일들의 signature verification 을 무시하도록 옵션 준다.
$ dsu --ignore-signature

 

Firmware upgrade하고 통신이 정상적으로 되는것을 확인하였다.

또한 서버 상태도 확인하였다.

  • 네트워크 인터페이스가 UP 된것
  • 게이트웨이로 ping
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
3: eno2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
5: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether f4:a3:91:c6:73:c0 brd ff:ff:ff:ff:ff:ff
    
$ ping 172.21.239.1
PING 172.21.239.1 (172.21.239.1) 56(84) bytes of data.
64 bytes from 172.21.239.1: icmp_seq=1 ttl=64 time=0.177ms
64 bytes from 172.21.239.1: icmp_seq=2 ttl=64 time=0.118ms
..

 

 

개념이 잘 이해가 안갔던 것들은 검색해서 모아두었다.

(요약한 내용은 본인의 생각을 적은것이므로 원작자의 의도와 다를 수 있다.)

 

 

ARP(Address Resoultion Protocol)는 IP주소를 가지고 MAC주소를 가져오기 위한 프로토콜

RARP(Reverse)는 반대로 MAC주소를 가지고 IP주소를 가져옴

https://peemangit.tistory.com/207

 

[Network] ARP, RARP,GARP 개념

1. ARP (Address Resolution Protocol) IP 주소를 이용해 상대방의 MAC 주소를 알아오는 프로토콜이다. ARP 요청·응답 완료되면 ARP table에 각 노드의 ARP 정보를 저장한다. ARP 요청: 특정 IP주소에 대해 MAC..

peemangit.tistory.com

LACP는 여러개의 이더넷포트를 하나로 묶어서 사용할 수 있어서

대역폭을 넓힐 수 있고, 하나의 포트에 장애가 발생해도 다른 포트에서 처리할 수 있어서 링크의 단절을 피할 수 있다.

https://devopsnet.tistory.com/39

 

LACP(802.1ax) 이야기

우리가 알고있는 Network에서 사용되는 LACP(Link Aggregation Control Protocol)는 여러 물리링크를 하나의 논리적인 링크로 생성함으로써 대역폭을 증가시키고 장애 발생시 정상적인 성능 저하(fault-tolerant)

devopsnet.tistory.com

SDU: 상향/하향 통신 레이어 간에 전달되는 실제 정보

PDU: 동일 레이어 내에서 데이터 단위

https://velog.io/@hidaehyunlee/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%84%B8%EA%B7%B8%EB%A8%BC%ED%8A%B8-%ED%8C%A8%ED%82%B7-%ED%97%B7%EA%B0%88%EB%A6%B4-%EB%95%90-PDU%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90

 

데이터? 세그먼트? 패킷? 헷갈릴 땐 PDU를 알아보자

모든 계층에서, 우리가 전송하는 데이터를 `데이터`라고 부를까? PDU를 알고난 후 부터는 그렇지 않을 것이다.

velog.io

 

 

 

'Infra' 카테고리의 다른 글

Python으로 Opendistro Account 생성하기  (0) 2021.03.17
Cloudfront와 S3를 이용한 웹 서비스 구성  (0) 2021.03.10
Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS Subnet 생성하기  (0) 2020.07.23
AWS VPC 생성하기  (0) 2020.07.23

기존에 Cognito를 이용해서 Kibana의 접근을 제한해왔었다.

기존에는 단순히 kibana 접근만 제한하고 있어서 audit 통과가 목적이었지만

운영하다보니 Role을 부여해서 세세하게 접근을 제한하고 싶어졌다.

Elasticsearch의 index단위로 접근을 제한하고 read/write 권한 조절하기 위하여

Opendistro를 이용하기로 했다.

 

Elasticsearch 설치형에서는 이미 사용중이었고

AWS의 ElasticSearch에 지원을 한지 좀 되었지만.. 이제 반영하려한다.

 

Launching Open Distro for Elasticsearch security features on Amazon Elasticsearch Service | Amazon Web Services

We are excited to announce that we are making new Open Distro for Elasticsearch security features available on Amazon Elasticsearch Service. Amazon Elasticsearch Service is frequently used for sensitive enterprise workloads, and today’s launch adds multi

aws.amazon.com

 

Open Distro의 API가 있겠거니하고 문서를 찾아본다.

 

API

Documentation for Open Distro for Elasticsearch, the community-driven, 100% open source distribution of Elasticsearch with advanced security, alerting, deep performance analysis, and more.

opendistro.github.io


Account Create 요청이다.

#### REQUEST

PUT _opendistro/_security/api/internalusers/<username>
{
  "password": "kirkpass",
  "backend_roles": ["captains", "starfleet"],
  "attributes": {
    "attribute1": "value1",
    "attribute2": "value2"
  }
}

 

backend role 대신에 일반 role을 맵팽하는 방식을 사용할 것이고,

attributes 정보는 아직은 안쓸것이라서 

password만 사용할 예정이다. (이것도 default pw로 처음 로그인할때 알아서 바꾸게 해줄 방법은 없으려나..)

 

1차로 구현했던 코드

아래의 내용은 본인 환경에 맞게 전부 수정해서 사용해야 한다.

 

참고로 opendistro_admin, opendistro_admin_pw는 실제 admin 계정의 것을 사용하거나, 계정관련 security menu 접근 권한이 있는 계정의 정보를 이용한다.

import json
import requests

def opendistro_create_user():
    user_name = 'testuser'
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/internalusers/%s' % (user_name)
    url = base_url + path
    payload = {'password': 'INITpassword1234!@#$', 'backend_roles': ['read_write_all_index']}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), data=payload)
    print(rs.content)

매뉴얼에 나와있는대로 PUT을 수행했다.

결과는 에러

b'{"error":"Content-Type header is missing","status":406}'

해더를 빼먹었으니 넣어준다.

 

2차로 구현한 코드

import json
import requests

def opendistro_create_user():
    user_name = 'testuser'
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/internalusers/%s' % (user_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'password': 'INITpassword1234!@#$', 'backend_roles': ['read_write_all_index']}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), data=payload, headers=headers)
    print(rs.content)

결과는 다시 에러

b'{"status":"error","reason":"Could not parse content of request."}'

data type이 문제로 보인다.

 

requests.put 할때 파라메터를 수정해주는데, 해결방안이 2개가 있다. 

  1. data=json.dumps(payload)
  2. json=payload

2안을 택했다.

3차로 구현한 코드 [성공]

import json
import requests

def opendistro_create_user():
    user_name = 'testuser'
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/internalusers/%s' % (user_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'password': 'INITpassword1234!@#$', 'backend_roles': ['read_write_all_index']}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), json=payload, headers=headers)
    print(rs.content)

결과는 성공이다.

b'{"status":"CREATED","message":"\'testuser\' created."}'

 

Role Mapping 관련해서는 

mapping 해주거나 backend_role을 사용하도록 해야한다.

다른 동료들이 나중에 Kibana에서 보고 처리하기 쉬울것 같아서 mapping 해주는 방식을 선택하였다.

#### REQUEST

PUT _opendistro/_security/api/rolesmapping/<role>
{
  "backend_roles" : [ "starfleet", "captains", "defectors", "cn=ldaprole,ou=groups,dc=example,dc=com" ],
  "hosts" : [ "*.starfleetintranet.com" ],
  "users" : [ "worf" ]
}

여기에서 나는 role만 매핑할거라서 사용하게될 정보는 users만 사용한다.

그리고 미리 role을 kibana에서 생성해두고 그것을 사용한다.

 

1차 시도한 코드

import json
import requests

   
def opendistro_mapping_role(user_name, role_name='read_write_limit'):
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/rolesmapping/%s' % (role_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'users': [user_name]}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), headers=headers, json=payload)
    print(rs.content)

돌려보니 되는줄 알았다.

문제는 users라고 되어있는것을 제대로 파악 못한것이 문제.

이런식으로 루프 돌려가면서 호출했더니 가장 마지막에 호출한 user 정보 1개만 남았다.

for user in user_list:

    opendistro_mapping_role(user)

 

 2차 시도한 코드는 원하는대로 동작 [성공]

import json
import requests

   
def opendistro_mapping_role(user_list, role_name='read_write_limit'):
    base_url = 'https://vpc-sfixer-applog-jdqfbp4ttozpwfxxxxxxxxxxxx.ap-eastsouth-1.es.amazonaws.com/'
    path = '_opendistro/_security/api/rolesmapping/%s' % (role_name)
    url = base_url + path
    headers = {'content-type': 'application/json'}
    payload = {'users': user_list}
    rs = requests.put(url, auth=('opendistro_admin', 'opendistro_admin_pw'), headers=headers, json=payload)
    print(rs.content)

1차에서 개별 사용자를 처리하려고 loop 돌렸던 것을 없애고 

그 사용자 list를 인자값으로 넘겼더니 제대로 mapping 된것을 kibana에서 확인하였다.

사용자 list라함은 이런 형태로 값이 저장되어있다.

  • user_list = ['user1', 'user2', 'user3', ... , ... , 'user100']

 

 

'Infra' 카테고리의 다른 글

인프라 개념 LACP  (0) 2022.06.10
Cloudfront와 S3를 이용한 웹 서비스 구성  (0) 2021.03.10
Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS Subnet 생성하기  (0) 2020.07.23
AWS VPC 생성하기  (0) 2020.07.23

 

Web service를 시작하기로 하였다.

CDN을 둬서 static contents들을 서빙하려하고 cloudfront를 사용하기로 결정하였다.

Data의 보관은 S3 bucket에 static contents를 두고 cloudfront에서 접근해서 가져가는 방식을 사용하기로 결정하였다.

 

기본 세팅

S3, Cloudfront, Route53 관련 세팅하는 것은 하나씩 읽어가면서 누르면 된다. 검색하면 포스팅한 글이 이미 많다.

개인적으로는 각 설정 항목에 대한 설정은 한번 자세히 보고 넘어야가야 한다는 생각이다.

혹은 cloudformation 템플릿을 이용해서 구성한다. 

CloudFront와 S3를 이용해서 서빙을 한다면 처음 세팅할때 이 부분을 반드시 "Yes"로 해주고 Identity는 Access S3 bucket content only through CloudFront를 선택한다.

만약 No로 한 경우에는 나중에 Origin 설정에서 바꾸려고 해도 바꿀수는 없고, Origin을 삭제하고 다시 만드는 방법이 있을 수 있겠다.

HTTPS로만 접근을 허용하겠지만
그렇다고 HTTP 요청을 다 버리고 싶진 않으니 Redirect 하도록 Behavior에서 설정해주었다.

 

TTL

TTL 설정을 통한 cache 전략에서 고민이 시작되었다.

평소에는 static 파일들을 추가만 할테니 TTL을 aws에서 default로 제공하는 것을 그냥 사용해도 아무런 문제가 없다.

문제는 hotfix. 

배포된 이미지 파일의 구문이 잘 못되서 급히 변경해야 되는 상황 같은 경우.

물론 Invalidations 기능이 있어서 긴급할때는 이 기능을 이용해서 cache를 다 날려버릴 수 있다.

AWS console에서 눌러가면서 하거나

 

아니면 awscli로 처리한다.

# sample

aws cloudfront create-invalidation --distribution-id $distribution_ID --paths "/*"

 

다시 TTL 설정으로 돌아와서 3개의 TTL 의미 파악을 못했다.

물론 HTTP Header에 Cache-Control: max-age=xx, Cache-Control: s-maxage=xx 같은 값이 없으면 default TTL인 것은 알겠으나, 
minimum TTL, maximum TTL 관련해서는 이 메뉴얼을 읽어보았지만 이해를 못했었다.

  • default TTL (Cache-Control, Expires header가 없는 경우)
  • minimum TTL
  • maximum TTL

 

그러던중에 이를 이해할 수 있게 정리한 포스팅을 찾았다.

  • 만약 Cache-Control 헤더의 max-age 값이 사용자가 정의한 minimum TTL과 maximum TTL 사이에 있는 경우, CloudFront는 maximum TTL에 지정된 시간에 대해 개체를 캐시합니다.
  • 만약 max-age 값이 사용자가 정의한 minimum TTL보다 작으면 CloudFront는 minimum TTL값에 대해 개체를 캐시합니다.
  • 만약 max-age 값이 사용자가 정의한 maximum TTL보다 큰 경우 CloudFront는 maximum TTL 값에 대해 개체를 캐시합니다.

대충 이해가 간다.

Cache-Contorl, Expires 해더를 이용해서 세팅을 해주면 TTL을 내가 원하는대로 맞춰서 사용할 수 있다는 것은 알겠다.

 

그럼 다시 Cloudfront로 돌아와서 Cache policies 중에 "Managed-CachingOptimized"의 TTL 세팅을 다시 본다.

  • Minimum TTL: 1 sec
  • Maximum TTL: 31536000 sec (1 year)
  • Default TTL: 86400 sec (1 day)

어떤 설정인지는 알겠는데 좀 더 확실하게 알아야겠다고 생각하고 메뉴얼을 다시 읽어 보았다.

AWS는 뉴얼을 잘 봐야하는 걸 알면서도 제대로 안보고 지나쳤던것이 문제였다.

이제서야 메뉴얼이 눈에 들어오기 시작한다.

메뉴얼을 자세히 보면 이해가 되겠지만 다시한번 적어보면서 이해를 해본다.

  • minimum TTL은 Min TTL, maximum TTL은 Max TTL로 표현한다.

표에 나오는 HTTP header

  • Cache-Control: max-age=<seconds>  (e.g. Cache-Control: max-age=1200)
  • Cache-Control: s-maxage=<seconds> (e.g. Cache-Control: s-maxage=1200)
  • Expires: <http-date> (e.g. Expires: Wed, 10 Mar 2021 07:28:00 GMT)
Origin 해더 Min TTL = 0 sec Min TTL > 0 sec (1초 보다 큼)
Origin object에
Cache-Control: max-age
헤더 추가
[CloudFront 캐싱]
Cloudfront는
Cache-Control max-age와 Max TTL의 값 중
더 작은 값 동안 캐싱


[Browser 캐싱]
Browser는
Cache-Control max-age 동안 캐싱

[CloudFront 캐싱]
Cloudfront는
Min TTL < max-age < Max TTL

- Cache-Control max-age 동안 캐싱
max-age < Min TTL
- Min TTL 동안 캐싱
max-age > Max TTL
- Max TTL 동안 캐싱

[Browser 캐싱]
Browser는
Cache-Control max-age 동안 캐싱

Origin object에
Cache-Control: max-age
헤더 추가 안함
[CloudFront 캐싱]
Cloudfront는 
default TTL
 동안 캐싱

[Browser 캐싱]
Browser 마다 다름
[CloudFront 캐싱]
Cloudfront는
Min TTL과 default TTL 둘중 더 값이 큰 값 동안 캐싱

[Browser 캐싱]
Browser 마다 다름
Origin object에
Cache-Control: max-age와
Cache-Control: s-maxage
헤더 추가 
[CloudFront 캐싱]
Cloudfront는 
Cache-Control s-maxage와 Max
 TTL의 값 중
더 작은 값 동안 캐싱


[Browser 캐싱]
Cache-Control max-age 동안 캐싱
[CloudFront 캐싱]
Cloudfront는
Min TTL < s-maxage < Max TTL

- Cache-Control s-maxage 동안 캐싱
s-maxage < Min TTL
- Min TTL 동안 캐싱
s-maxage > Max TTL
- Max TTL 동안 캐싱

[Browser 캐싱]
Browser는
Cache-Control max-age 동안 캐싱
Origin object에
Expires 헤더 추가
[CloudFront 캐싱]
Cloudfront는 
Expires의 날짜와 Max
 TTL의 값 중
더 빨리 만료되는 동안 객체를 캐싱


[Browser 캐싱]
Browser는
Expires의 날짜와 시간 까지 캐싱
[CloudFront 캐싱]
Cloudfront는
Min TTL < Expires < Max TTL

- Expires의 날짜와 시간 까지 캐싱
Expires < Min TTL
- Min TTL 동안 캐싱
Expires > Max TTL
- Max TTL 동안 캐싱

[Browser 캐싱]
Browser는
Expires의 날짜와 시간 까지 캐싱
Origin object에
Cache-Control: no-cache, no-store
혹은 private 
헤더 추가
CloudFront, Broser는 헤더의 설정에 따른다.

CloudFront에서 Cache-Control: no-cache 처리방식은 링크 참고
[CloudFront 캐싱]
Cloudfront는 Min TTL 동안 캐싱

[Browser 캐싱]
Browser 헤더의 설정을 따름

 

 

다음으로는 나의 static file들이 S3에 있으니 S3에 object 세팅을 해줘야 할 것 같다.

S3 object에 Metadata을 이용하면 되겠다.

일단 그럼 테스트를 한번 해본다.

테스트라서 빌드 디렉터리를 통째로 옵션을 줬지만,, 실제로는 파일 확장자 단위로 하거나 좀 더 잘게 나눠서 할 예정이다.

(react app 만들고 빌드할 설정과 aws s3 sync할 설정에 대한 설명은 제외,, 다른 방법으로도 테스트는 가능하므로)

> create-react-app sample-deploy
...
...

> cd sample-deploy
> yarn build
...
...

> aws s3 sync ./build s3://test-upload-bucket --metadata='{"Cache-Control":"max-age=300"}'
...
...

원하는대로 metadata가 세팅이 되었는지 확인해본다.

 

Value는 내가 원하는대로 올라갔는데 Key 값이 다르다.

"x-amz-meta-"로 시작하는 헤더는 User defined(사용자 정의) 메타데이터 HTTP 헤더로 별도로 구분하기 위한 키워드인데 이것은 원래 하려던것이 아니다.

 

다른 옵션을 찾아서 옵션을 바꿔보았다. '--cache-control' 로 해보니 원하는대로 Key, Value가 세팅되었다.

> aws s3 sync ./build s3://test-upload-bucket -cache-control max-age=1200
...
...

 

S3 Object 접근 제한

외부에서 S3 Object에 직접적인 접근은 제한을 걸고 싶다.

그래서 크게 2개의 접근만 허용해주고 나머지는 제한하려고 했다.

  • 업무하는 사무실의 접근
  • CloudFront의 접근

사무실에서의 접근은 가장 편하고 직관적인 IP 허용으로 처리했다.

CloudFront에서의 접근은 Origin Access Identity를 이용해서 허용해주었다. (ColudFront의 Origin 설정에서 확인)

 

S3의 Bucket에서 Permission 탭에 있는 Bucket policy 세팅 결과이다.

주요 정보들은 x, y 같은 것으로 바꿔두었다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test-upload-bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "x.x.x.x/32",
                        "y.y.y.y/32"
                    ]
                }
            }
        },
        {
            "Sid": "CloudfrontOAI",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2ZZZ2IRJXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test-upload-bucket/*"
        }
    ]
}

테스트를 해본다.

wifi를 끈 휴대폰을 이용해서 S3 url에 직접 접근해았더니 Access Denied 발생한다.

Cloudfront에 접근해서 보니 잘 보인다.

참고로 Route53에 dns 세팅을 미리 해두었고 그것을 Alternative Domain Names(CNAMEs)에 추가해서 이용하였다. 

이 부분은 마우스 클릭 몇번이면 되므로 패스.

 

나머지는 운용해나가면서 적절히 맞춰가야겠는데

Behaviors에서 Path Pattern 적용해서 Cache policy 적용해주는것 (개발팀과 협의 (modify없이 add만)? 배포할때마다 버저닝?)

Error Pages에서 에러 발생에 대한 응답 페이지/코드 세팅해주는 정도를 추가로 맞추게 되지 않을까 싶다.

거기에 Origin이 늘어나면 거기에 따른 추가 설정들도..

'Infra' 카테고리의 다른 글

인프라 개념 LACP  (0) 2022.06.10
Python으로 Opendistro Account 생성하기  (0) 2021.03.17
Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS Subnet 생성하기  (0) 2020.07.23
AWS VPC 생성하기  (0) 2020.07.23

Terraform

[ 사전적 의믜 ]

Terraforming(테라포밍)은 지구가 아닌 다른 행성 및 위성, 기타 천체의 환경을 지구의 대기 및 온도 생태계와 비슷하게 바꾸어 인간이 살 수 있도록 만드는 작업으로 화성탐사 관련해서 종종 등장하는 용어입니다.

하시코프에서 이 제품의 이름을 왜 이렇게 지었을지 생각해보았습니다.

단어 뜻에서 각기 다른 모든 vendor의 인프라 환경을 비슷하게 바꾸어 서비스를 할 수 있도록 만드는 작업을 하는 도구라고 느껴집니다.

 

[ 특징 ]

테라폼은 Chef, Puppet, 과 같이 Infrastructure provisioning 툴로 분류할 수 있습니다.

source: http://blog.shippable.com/the-future-of-devops-is-assembly-lines

The key features of Terraform are:

  • Infrastructure as Code: Infrastructure is described using a high-level configuration syntax. This allows a blueprint of your datacenter to be versioned and treated as you would any other code. Additionally, infrastructure can be shared and re-used.  👉 버전으로 인프라 이력관리, 인프라 공유 및 재사용

  • Execution Plans: Terraform has a "planning" step where it generates an execution plan. The execution plan shows what Terraform will do when you call apply. This lets you avoid any surprises when Terraform manipulates infrastructure. 
    👉 plan 단계를 거치면서 인프라에 어떤 변화가 생길지 볼 수 있음

  • Resource Graph: Terraform builds a graph of all your resources, and parallelizes the creation and modification of any non-dependent resources. Because of this, Terraform builds infrastructure as efficiently as possible, and operators get insight into dependencies in their infrastructure. 👉 모든 리소스를 그래프로 작성하고 종속되지 않은 리소스의 추가와 변경을 병렬로 처리해서 효율적으로 인프라를 구축하고 각 리소스의 의존성을 확인 할 수 있음

source: https://www.terraform.io/docs/commands/graph.html

  • Change Automation: Complex changesets can be applied to your infrastructure with minimal human interaction. With the previously mentioned execution plan and resource graph, you know exactly what Terraform will change and in what order, avoiding many possible human errors. 👉 terraform plan, 그 결과로 나오는 resource graph로 어떤 순서로 변경이 발생할지 미리 확인할 수 있어서 휴먼에러를 많이 줄일 수 있음

 

[ 버전 관리 ]

다른 패키지와 마찬가지로 일정 시간이 지나면 new feature, bug fix등의 작업으로 upgrade 될것이고 그에 따라 맞춰주는 작업이 필요해집니다. 시간이 지나면 버전관리할 필요가 생기게 되는데 이때 크게 2가지 방법을 사용할 수 있습니다.

[ Use cases ]

이중에서 제가 Terraform을 선택하려는 이유는

  • Heroku App setup  : -
  • Multi-Tier Applications : API 서버, 캐싱 서버등 추가되는 레이어를 개별적으로 확장
  • Self-Service Clusters : 서비스 구축과 확장한 방법들을 코드화
  • Software Demos : -
  • Disposable Environments : 서비스에 따라서 Dev, Stage 환경을 빠르게 구성해주었다가 폐기
  • Software Defined Networking : AWS VPC 부터 네트워크 구성을 코드화
  • Resource Schedulers : -
  • Multi-Cloud Deployment : 관리를 단순화 시켜 대규모 멀티 클라우드 인프라 용이

 

 

'Infra' 카테고리의 다른 글

Python으로 Opendistro Account 생성하기  (0) 2021.03.17
Cloudfront와 S3를 이용한 웹 서비스 구성  (0) 2021.03.10
AWS Subnet 생성하기  (0) 2020.07.23
AWS VPC 생성하기  (0) 2020.07.23
AWS EKS Service Role 생성 (IAM)  (0) 2020.07.23

안녕하세요 쿤드입니다. 🍀

이번엔 Subnet을 생성해보려고 합니다.

 

제가 사용하는 리전에는 Availability Zone이 3개가 있긴한데 

2개의 Zone만 사용해서 private용 2개, public용 2개 총 4개를 생성했습니다.

 

IPv4 CIDR block으로 IP 범위를 지정해주었는데

각 서브넷당 최대 4094개의 host를 할당 해 줄 수 있도록 netmask는 20으로 설정했습니다.

  • 10.3.0.0/20 (10.3.0.1 ~ 10.3.15.254)
  • 10.3.16.0/20 (10.3.16.1 ~ 10.3.31.254)
  • 10.3.32.0/20 (10.3.32.1 ~ 10.3.47.254)
  • 10.3.48.0/20 (10.3.48.1 ~ 10.3.63.254)

Subnet을 생성하고 나면 각 서브넷마다 할당할 수 있는 IP 주소 여분의 개수도 확인할 수 있습니다.

 

서브넷을 세팅하고 나면 Route Table을 설정합니다. 

 

클릭하고 들어간 후에 할당해줄 subnet을 선택하고 서로 Associate시켜 줍니다.

 

 

그리고 나머지 Route Table은 필요한 경우에 Edit routes를 이용해서 정보를 추가해줍니다.

 

 

IPSec VPN을 이용해서 네트웍 설정을 한 경우에는 위의 메뉴에서 직접 설정이 불가능했었습니다.

저 같은 경우에는 자체 설정한 Site-to-Site VPN 설정, 직접 구축한 OpenVPN에 대한 라우팅 설정을 할때 직접 추가 했었습니다.

 

 

나머지 작업은

Public으로 사용하기 위한 subnet에서 사용할 Internet Gateway

Private으로 사용하기 위한 subnet에서 사용할 NAT Gateway

  • 참고로 NAT Gateway 생성할 때는 여기에서 사용할 때는 Associate Elastic IP address를 클릭하면 알아서 EIP를 생성해서 할당해줍니다.
  • NAT Gateway를 삭제 혹은 이미 Associate Elastic IP address를 클릭하고 NAT Gateway 생성을 취소한 경우 EIP가 이미 생성되어 있으므로 release 시켜서 불필요한 비용 발생하지 않도록 합니다.

설정만 해주면 기본적인 VPC 구성은 되었다고 볼 수 있습니다.

'Infra' 카테고리의 다른 글

Cloudfront와 S3를 이용한 웹 서비스 구성  (0) 2021.03.10
Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS VPC 생성하기  (0) 2020.07.23
AWS EKS Service Role 생성 (IAM)  (0) 2020.07.23
AWS EKS Cluster 세팅  (0) 2020.07.23

안녕하세요 쿤드입니다. 🍀 

이번엔 VPC 생성하는 방식에 대해서 확인해보겠습니다.

 

AWS VPC

  • Virual Private Cloud
  • AWS 사용자가 정의한 전용 가상 네트워크입니다.

 

생성하기

  • 적절한 이름을 입력하고
  • VPC에서 사용할 IP 주소의 범위를 정합니다.
  • 저는 IPv6는 사용하지 않아서 default인 No IPv6 CIDR Block을 선택했습니다.
  • Tenancy
    • default : 인스턴스가 공유된 하드웨어에서 실행
    • dedicated : 인스턴스가 단일 테넌트 하드웨어에서 실행

 

 

VPC를 생성하고 나면 통신을 위해서

Subnet을 세팅합니다.

'Infra' 카테고리의 다른 글

Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS Subnet 생성하기  (0) 2020.07.23
AWS EKS Service Role 생성 (IAM)  (0) 2020.07.23
AWS EKS Cluster 세팅  (0) 2020.07.23
S3에 SQS notification event 추가할때 권한 설정  (0) 2020.06.26

안녕하세요 쿤드입니다. 🍀

 

AWS IAM (Identity and Access Management)은

  • AWS Identity and Access Management(IAM)는 AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스입니다.
  • IAM을 사용하여 리소스를 사용하도록 인증(로그인) 및 권한 부여(권한 있음)된 대상을 제어합니다.

Step 1. EKS Cluster용 Role 생성

  • EKS 선택

 

 

  • EKS - Cluster 선택

 

  • 적절히 Tag 설정
  • Role 관련 name 및 description 세팅 

 

  • Create role 하면 Role이 생성됩니다.
  • 이후에는 EKS 메뉴로 가서 Cluster Service Role의 refresh 버튼을 누르면 보이게 되고 선택해주면 됩니다. 

 

이 Role에 추가한 policy를 확인해보겠습니다.

AmazonEKSClusterPolicy(AWS Managed policy)는 4개 서비스의 권한과 1개의 IAM 인증 권한을 허용합니다.

  • AutoScaling
  • EC2
  • ELB
  • KMS
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:UpdateAutoScalingGroup",
                
                "ec2:AttachVolume",
                "ec2:AuthorizeSecurityGroupIngress",
                
                "ec2:CreateRoute",
                "ec2:CreateSecurityGroup",
                "ec2:CreateTags",
                "ec2:CreateVolume",
                
                "ec2:DeleteRoute",
                "ec2:DeleteSecurityGroup",
                "ec2:DeleteVolume",
                
                "ec2:DescribeInstances",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVolumes",
                "ec2:DescribeVolumesModifications",
                "ec2:DescribeVpcs",
                "ec2:DescribeDhcpOptions",
                "ec2:DescribeNetworkInterfaces",
                
                "ec2:DetachVolume",
                
                "ec2:ModifyInstanceAttribute",
                "ec2:ModifyVolume",
                
                "ec2:RevokeSecurityGroupIngress",
                
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
                "elasticloadbalancing:AttachLoadBalancerToSubnets",
                
                "elasticloadbalancing:ConfigureHealthCheck",
                
                "elasticloadbalancing:CreateListener",
                "elasticloadbalancing:CreateLoadBalancer",
                "elasticloadbalancing:CreateLoadBalancerListeners",
                "elasticloadbalancing:CreateLoadBalancerPolicy",
                "elasticloadbalancing:CreateTargetGroup",
                
                "elasticloadbalancing:DeleteListener",
                "elasticloadbalancing:DeleteLoadBalancer",
                "elasticloadbalancing:DeleteLoadBalancerListeners",
                "elasticloadbalancing:DeleteTargetGroup",
                
                "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                "elasticloadbalancing:DeregisterTargets",
                
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeLoadBalancerAttributes",
                "elasticloadbalancing:DescribeLoadBalancerPolicies",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeTargetGroupAttributes",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeTargetHealth",
                
                "elasticloadbalancing:DetachLoadBalancerFromSubnets",
                
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:ModifyLoadBalancerAttributes",
                "elasticloadbalancing:ModifyTargetGroup",
                "elasticloadbalancing:ModifyTargetGroupAttributes",
                
                "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
                "elasticloadbalancing:RegisterTargets",
                
                "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer",
                "elasticloadbalancing:SetLoadBalancerPoliciesOfListener",
                
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com"
                }
            }
        }
    ]
}

'Infra' 카테고리의 다른 글

AWS Subnet 생성하기  (0) 2020.07.23
AWS VPC 생성하기  (0) 2020.07.23
AWS EKS Cluster 세팅  (0) 2020.07.23
S3에 SQS notification event 추가할때 권한 설정  (0) 2020.06.26
AWS의 Cloudwatch와 CloudTrail의 차이  (0) 2020.06.01

안녕하세요 쿤드입니다. 🍀 

이번엔 EKS Cluster를 생성해 보겠습니다.

 

Amazon EKS

  • Amazon EKS는 Kubernetes의 Control Plain or Node를 설치, 운영 및 유지보수 할 필요 없이 AWS에서 Kubernetes를 손쉽게 실행할 수 있는 관리형 서비스입니다.
    • Kubernetes는 컨테이너화된 애플리케이션의 배포, 조정 및 관리 자동화를 위한 오픈 소스 시스템입니다.

 

구축하기

Step 1. 클러스터 설정 (Configure cluster)

  • Name과 version을 선택합니다.
  • Cluster Service로 사용할 IAM role을 미리 생성해두고 선택합니다.
  • Tag는 적절하게 추가합니다. (나중에 관리 및 비용 구분하기 용이하도록)

 

Step 2. 네트워킹 설정 (Specify networking)

VPC(Virtual Private Cloud) 선택

  • 원하는 VPC를 선택합니다.
  • 필요한 경우 새로운 VPC를 생성합니다.

 

Subnet 선택

  • EKS 클러스터를 생성할때는 2개 이상의 서브넷이 필요합니다.
  • 물론 1개의 subnet에 public, private으로 구분할 수도 있는데 그렇게 2개 서브넷을 선택한 경우에는 이런 에러가 발생합니다.

  • 노드를 위치시킬 VPC를 기존 사용하던 곳에 할지 완전히 분리하도록 새로운 VPC를 생성할지 결정한 후에 선택합니다.
  • Endpoint Access 인 경우는 Private으로 설정하면 local pc에서 kubectl 설정하여 접근할때 아래의 문제로 인해서 추가적인 네트웍 설정이 필요합니다.
    • Unable to connect to the server: dial tcp 172.xx.xxx.xx:443: i/o timeout

 

 

나머지는 로깅 할지 여부 설정, 그리고 review 이후에 생성하면 됩니다.

+ Recent posts