.

[AWS] AWS Transfer Family

by 담배맛구마

 

뭘 어떻게 기록해둘까 고민하다가, 포이트가 될만한 안건들만 적기로 했다

 

 

General

S3에 파일을 안전(보안)하게 전송하기 위한 서비스이다. 이 서비스는 파일 전송을 하는 워크프로우를 AWS로 마이그레이션하는 것을 타겟으로 하고 있다. 현재 지원하는 프로토콜은 FTP, SFTP, FTPS 이다.

각 프로토콜이 가지는 몇 가지 특성에 대한 제약이 존재한다. 다음의 문서를 참고한다.
https://docs.aws.amazon.com/transfer/latest/userguide/getting-started-use-the-service.html

 

완전 관리형 서비스로써 서버 인스턴스나 인프라를 구축할 필요가 없고 클라이언트 측에서의 설정값 수정이 필요가 없다. 기존에 클라이언트가 접속하던 hostname을 AWS Transfer Family에서 만든 서버로 연결시키고, 사용자를 추가하고 권한을 설정하면 끝난다. 비용은 서비스를 사용한 시간과 파일의 용량으로 부과된다. 테스트하고 나서는 재빠르게 삭제해주자. 

 

 

 

Scope-down Policy

chrooted. 서비스 계정별로 서비스되는 루트 디렉토리에 대해서 설정하고 가상의 디렉토리와 파일을 연결지어 버릴 수 있다. 적용하는 방법으론 IAM Policy 양식으로 작성하거나 Custom IdP에서 HomeDirectory- 관련 옵션을 사용하면 된다.

 

IAM Policy

IAM Policy으로 작성하는 경우에는 Transfer Family에서만 전처리되어 동적으로 변환되는 변수들을 쓸 수 있다. 예를 들어 ${Transfer:UserName} 등이 있다.

 

Custom Idp의 HomeDirectroy-

말 그대로 IdP가 서버로 반환해주는 값에 다가 관련된 내용들을 정의해주면된다. 일단 다음과 같이 HomeDirectoryType에 대해서 LOGICAL값을 설정해야 한다.

[{ "HomeDirectoryType": "LOGICAL" }]

그 다음에 HomeDirectoryDetail에 JSON Array로 작성하면 된다.

[{"Entry": "/", "Target": "/mybucket/jess"}]
OR
[{"Entry": "/", "Target": "/mybucket/${Transfer:UserName}"}]

쫌 더 응용하면 더 괴랄하게 만들 수 도 있다.

[
{"Entry": "/pics", "Target": "/bucket1/pics"}, 
{"Entry": "/doc", "Target": "/bucket1/anotherpath/docs"},
{"Entry": "/reporting", "Target": "/reportingbucket/Q1"},
{"Entry": "/anotherpath/subpath/financials", "Target": "/reportingbucket/financials"}
]

 

위와 같은 방법으로 HomeDirectoryType가 LOGICAL이고 Entry, Target Pair가 설정된 경우에는 HomeDirectory를 정의할 필요가 없다. 당연하겠지만 해당되는 버킷에 대해 권한은 필수적이다. 사용한다면 복잡한 Scope-down Policy 빌드와 Client 측의 수정사항을 줄일 있고 보안적인 이점을 얻을 있다.

 

 

 

End Point Type

주의 할점은 해당 서비스에서 End Point라고 하는 것들은 AWS Transfer Family로 구축한 서버를 칭한다. 즉, 이 서버를 어디에 어떻게 배치 시킬거냐에 대한 설정으로 생각하면 된다. 유연하게 선택하면 될 것 같다.

 

Public Access

그냥 닉값한다. 생성하게 되면, Public Dynamic IP를 가진 Public DNS를 제공해준다. 이 DNS에 Route53으로 사용자가 가지고 있는 DNS를 붙일 수 있도록 설정을 제공하고 있긴 하다.
단점으론, 외부에 대한 접근제어가 매우 제한적이다. 최근에 Source IP에 대한 제어 기능이 추가됬다고 하던데, 확인해보니 자격 증명 공급자로 Custom IdP를 사용할때에만 가능하다.

 

VPC_ENDPOINT

이거는 Console에서는 확인이 불가능하고 CLI, SDK를 통해서만 가능하다. 및의 VPC Hosted 2개로 대체되었다고 보면될 것 같다. 웃긴건 이 타입에 대한 자료가 거의 전무하지만 찾아 보면 한 두개는 있다.

 

VPC Hosted with internet-facing

VPC Hosted들은 기본적으로 ENI와 Interface 타입의 EndPoints을 생성해서 서비스된다. internet-facing의 경우에는 생성과정에서 ENI에 EIP를 붙이는 방식이다. EIP를 쓰니까 Public Static IP를 얻을 수 있고 이에 따른 Public DNS도 얻을 수 있다. 또한 Route53과 연계도 가능하다. 아울러, Subnet 내부니까 Private Static IP도 할당된다. 접근제어로 NACL, SG를 기본적으로 쓸 수 있을 것이고 Custom IdP에서도 가능할 것이다.

 

VPC Hosted with internal

이거는 위의 internet-facing의 ENI가 Private Subnet에 위치한다고 생각하면 된다. ENI에 Private Static IP만 붙는다. Private DNS도 제공되긴 한다. 접근제어는 동일하게 NACL, SG 그리고 Custom IdP이다.

 

EndPoint를 생성하니까 On-premise 환경과 연동되는 TGW, DX, VPN에서도 사용이 가능하고 VPC 간의 연동도 가능하다. AWS에서 선택 기준에 대해서 간략하게 테이블로 정리한 자료를 참고하면 좋을 것 같다.

https://aws.amazon.com/premiumsupport/knowledge-center/aws-sftp-endpoint-type/

 

 

 

Identity Provider

제일 난해했던 부분이다. 개념이 어렵거나 그런건 아니다. 정확하게 어떤 정보가 어떻게 흐른다는 지 확인하는게 어려웠다. 서버를 구축할 때, 다음의 두 가지 유형의 IdP를 설정할 수 있다.

 

Service Managed

서비스 자체적으로 사용자부터 인증까지 알아서 해주는 유형이다. 서비스 계정별 SSH Public Key를 유지관리하면서 사용자 인증을 하기 때문에 SFTP 프로토콜인 경우에만 사용할 수 있다. 또한, Password 인증이나 출발지 IP에 대한 접근제어가 지원되지 않는다. 그냥 말그대로 Key를 통한 인증만 해준다는 의미이다.
서비스 계정에 대한 관리도 서비스 내에서 수행하게되는데, 서버를 구축하고나서 콘솔이나 api, sdk를 통해 서비스 계정을 생성하고 설정을 할 수가 있어서 관리적 이점이 어느정돈 있는 것 같다.

Custom IdP

REST 타입의 API Gateway를 통해 인증을 수행하는 방식이다. 일반적으로 Lambda를 메소드에 붙여서 인증과정에 수행하는 식으로 구성하는 것 같다. Transfer Family에서 제공하는 모든 기능을 사용할 수 있다. SFTP의 경우 Key인증을 실패하면 Password로 재인증을 한다거나 어떤 프로토콜로 접속을 했는지, 출발지 IP는 어떻게 되는지에 대해 인증과정에서 제어할 수 있게 해준다.

 

다루고 싶은건 Custom IdP이다. 어차피 Service Managed의 사용자관리 부분을 제외한 모든 기능을 가져가기 때문이다.

 

Custom IdP를 구성할 때, 가장 난해했던 부분은 구축한 서버가 어떻게 IdP(API Gateway)와 통신하고, 또 내부적으로 어떤 결과값을 반환해야되는지에 대해서 명확하게 이렇게 저렇게 된다라고 명시되어 있지 않기 때문이다. 수 많은 Documents와 기술블로그들을 참조하여 비교,실험 결과 다음과 같은 결론을 얻을 수 있었고 순차적으로 정리해본다.

 

•[1] Server(Transfer Family) to IdP(API Gateway)

GET /servers/{serverId}/users/{username}/config?sourceIp=1.1.1.1&protocol=SFTP
...
Password: P@ssword
...

서버에서는 HTTP Request의 Get method로 위와 같은 URI와 Query string, Header로 인증정보를 IdP에 전송하게 된다. 딱 보면 느낌오듯이 serverId와 username, sourceIp, protocol, Password라는 정보가 전부이다.

serverId : resource path에서 정의되는 정보
username : resource path에서 정의되는 정보
sourceIp : HTTP Query 구문에 정의되는 정보 (옵션)
protocol : HTTP Query 구문에 정의되는 정보 (옵션)
Password : HTTP Requset Header 구문에 정의되는 정보(옵션)

serverId와 useranme은 URI에 반드시 포함되어야 하는 필수적인 정보이다. sourceIp와 protocol은 부가적인 옵션이고 Password의 경우 인증요소로 Password를 사용했을 때에 Header에 추가된다.

 

[2] Insdide IdP(API Gateway to Lambda)

{
  "username": "$input.params('username')",
  "Password": "$util.escapeJavaScript($input.params('Password')).replaceAll("\\'","'")",
  "protocol": "$input.params('protocol')",
  "serverId": "$input.params('serverId')",
  "sourceIp": "$input.params('sourceIp')"
}

그냥 위 5가지 정보를 JSON으로 묶은다음에 POST method로 Lambda에 전송한다. Lambda에서는 event 변수를 통해 참조한다.

 

[3] Insdide IdP(Lambda to API Gateway)

[필수항목]
Role : S3에 접근할 수 있는 Policy를 가진 Role의 Arn

[옵션항목]
Policy : Scope-down Policy에 대해서 JSON 포맷 (옵션)
  * 해당 Policy가 적용(?)될 때, 전처리되는 변수가 있으니 활용하면 유연하게 사용할 수 있다.
  * 변수목록 : ${Transfer:UserName}, ${Transfer:~~~}, ${Transfer:~~~}
  
PublicKeys: 사용자가 Password를 입력하지 않았다면, 접속하려는 계정의 Public Key를 입력
  * 물론, SFTP의 경우에만 사용가능하다.
  
HomeDirectory : 사용자 계정의 HomeDirectory를 지정할 수 있다.
  * 이거만 정의한다고 Chroot와 같은 효과를 제공하지는 않는다.

HomeDirectoryType: "PATH" 혹은 "LOGICAL" 값이며 
  * HomeDirectory로 제공한 경로를 사용자에게 절대값으로 보여주려면 "PATH"
  * HomeDirectory로 제공한 경로를 '/'로 보여주려면 "LOGICAL"

HomeDirectoryDetails : JSON 양식으로 Entry와 Target 페어의 리스트
  * 당연히 HomeDirectoryType가 "LOGICAL" 인 경우에 사용가능하다.
  * 이 기능으로 Logical Direoctry처럼 Cross(-Account)-Bucket 등의 구성이 가능하다.
  * 이걸 정의한 경우 HomeDirectory 값은 없어도 된다.

필수적인 Role과 옵션인 Policy, PublicKeys, HomeDriectory- 들이 있다. 이걸 그냥 JSON으로 묶은다음에 POST method 보내는 방식이다.

 

[4] IdP(API Gateway) to Server(Transfer Family)

{
  "$schema":"http://json-schema.org/draft-04/schema#",
  "title":"UserUserConfig",
  "type":"object",
  "properties":{
    "Role":{
      "type":"string"
    },
    "Policy":{
      "type":"string"
    },
    "HomeDirectory":{
      "type":"string"
    },
    "HomeDirectoryType":{
      "type":"string"
    },
    "HomeDirectoryDetails":{
      "type":"string"
    },
    "PublicKeys":{
      "type":"array",
      "items":{
        "type":"string"
      }
    }
  }
}

위아 같이 응답되는 Payload의 스키마를 정의한 것이다.

 

 

 

반응형

'Cloud' 카테고리의 다른 글

[AWS] How to get EC2 Windows instance password  (0) 2020.09.05
[AWS] AWS Code Series  (6) 2020.06.22
[AWS] SSH connect to bastion host by name tag  (0) 2020.05.10

블로그의 정보

정윤상이다.

담배맛구마

활동하기