Windows의 기본 VPN설정으로 Netplix접속시 주의사항

목적 외국에서 한국 Nexplix를 보고 싶다. 하지만 유료 VPN은 별로 사용하고 싶지 않다. 수시로 접속 거부를 당하면서 요금을 지불하고 싶지는 않다. 해결책 부모님 댁에 VPN서버를 지원하는 무선공유기를 한대 설치해 드리고 나는 외국에서 VPN으로 접속하여 Nexplix를 감상한다! 상황 공유기에 설정한 VPN에 iPad, Macbook으로 접속하면 문제 없이 한국 Netplix로 접속되는것을 확인했다. Windows11에서는 기본 VPN으로 iptime의 VPN에 접속하면 일본 Netplix로 접속 된다. 원인 처음에는 VPN의 Split Tunneling 문제가 아닐까 싶었다. Windows의 VPN설정에서는 Split Tunneling설정이 보이지 않았으므로 Power Shell에서 확인해 보았지만 Split Tunneling은 설정되어 있지 않았다.  결론부터 말하면 원인은 DNS서버였다. 이유는 모르겠지만 MacBook에서는 VPN접속시, DNS서버도 VPN서버의 DNS가 자동으로 설정되었는데 Windows11에서는 DNS서버가 변경되지 않아 한국 지역으로 인식되지 않았던 것으로 추측. Solution Windows11의 VPN접속 설정에서 접속시의 DNS서버를 한국의 공유기 IP로 지정을 해주었다. 그리고 IPv6이용설정을 해제하여 IPv4만 이용하도록 설정하니 문제 없이 접속되었다. 다음 문제 미니PC를 한대 구매하여 모든 설정을 마쳤지만 매번 키보드/마우스로 조작하는게 귀찮아 Remote Desktop으로 접속하는 것을 생각했다. 미니PC에 접속할때는 iPad를 이용할 계획인데 현재 찾아본 바로는 Console접속을 지원하는 Application이 없는 듯 하다. RemoteDesktop으로 접속하면 현재 TV에 연결해 놓은 세션은 꺼져버리니 Console로 접속가능한 어플리케이션이 필요하다. TeamView를 이용하니 어느정도 문제가 해결되긴 했지만 여기저기 조그마한 문제점들이 있어 고민중.

slack+slash command+API Gateway를 이용한 SSM 명령실행

목표

slack에서 slash command 를 이용하여 특정 명령어를 입력하면 SSM을 이용하여 지정한 ec2에서 지정된 명령을 실행하여 그 결과를 slack 에 출력한다. 여기에서는 각 ec2에서 free -m 명령을 실행 한 후 그 결과를 출력하도록 한다.

전제조건 : 대상 EC2는 ssm을 이용한 명령실행이 가능한 상황이어야 한다.

AWS설정

IAM 설정

slash command를 api gateway에서 받은 후, lambda에서 ssm을 호출한다. 그러기 위해서 lambda 함수에는 ssm과 로그 출력을 위한 cloudwatch logs 에 대한 권한이 필요하다.

  • IAM 에서 role을 선택하여 role을 작성
  • lambda를 선택해주고 일단 다음, 다음을 클릭하여 적당한 이름을 주고 role을 생성하였다.
  • 작성한 role을 선택후 「AmazonSSMFullAccess」AWS관리 Policy를 추가
  • inline policy를 선택하여 아래 json내용으로 적당한 이름을 지정하여 추가(이외에도 쓸일이 있다면 policy를 따로 생성한후 지정하는 것도 좋다. 이 policy가 없으면 cloudwatch logs에 로그 출력이 불가능.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "*"
        }
    ]
}

Lambda 함수 작성

lambda를 먼저 만드느냐, api gateway를 먼저 만드느냐 정해진 방법은 없다. 각 장단점이 있고 익숙한 방식이 있을터이니 편한 방법으로 작성해도 문제 없다. 최종적으로 api gateay를 trigger로 지정한 lambda function이 실행되면 OK.

  • lamda에서 함수 작성을 선택하여 Author from scratch를 선택
    • Function name을 적당히 넣어주고, Runtime은 Python3.8을 지정
    • Execution role에서 Use an existing role을 선택후 위에서 작성한 role을 지정하여 create function.

여기서 add trigger를 클릭하여 api gateway를 지정할 수도 있지만, 난 따로 만들겠다.

API Gateway 설정

  • api gateway에서 Create API를 선택후, REST API를 작성
  • API name을 적당히 입력해 주고 API를 생성
  • Resource를 선택후 Action에서 Create Resource를 선택 후 적당한 이름을 주고(여기에선 free를 지정) resource를 생성
  • /free 를 선택후 Action에서 Create Method를 선택후 Any를 지정
  • Intergration type에서 Lambda Function지정후 Region확인 하고 Use Lambda Proxy Intergration을 선택
  • 위에서 작성한 Lamda Function 이름을 지정 하여 Save하고 Permisson 추가에서 OK
  • Method Execution이 표시되면 Method Execution에서 Response Body for 200의 application/json 을 삭제
  • 완성된 any를 선택 후, actions에서 deply api를 선택하여 deply한다.
  • 왼쪽에서 stages를 선택하면 지정한 stage가 생성되어 있다. /free 를 확인하면 Invoke URL가 생성되어 있으니 메모
  • lambda function을 확인하면 trigger에 지정한 api gateway가 설정되어 있는 것을 확인

Lamda 코드

잘 알지도 못하는 python으로 겨우겨우 만들어 냈다. python다운 코드가 아니지만 잘 모르니 어쩔 수 없다.

import boto3
import json
import time
import requests

from urllib.parse import parse_qs

SLACKTOKEN = '<slack token>'
target_instances = ['<대상 ec2 ID>','대상 ec2 ID','대상 ec2 ID']

def command(ssm, instance, commands):
    r = ssm.send_command(
        InstanceIds = [instance],
        DocumentName = "AWS-RunShellScript",
        Parameters = {
            "commands": [
                commands
            ]
        }
    )
    command_id = r['Command']['CommandId']
    while True:
        time.sleep(0.2)
        res = ssm.list_command_invocations(
            CommandId = command_id,
            Details = True
        )

        invocations = res['CommandInvocations']
        status = invocations[0]['Status']
        print ("Get status : " + status)
        if status == "Failed":
            return ("Command 실행 에러")
        elif status == "Success":
            print ("Success!! return command result at " + instance)
            account = invocations[0]['CommandPlugins'][0]['Output']
            return account
        else:
            print ("Waiting Lambda function for 0.2s")


def lambda_handler(event, context):
    # TODO implement
    print ("Start Script")
    params = parse_qs(event['body'])
    token = params['token'][0]
    user = params['user_id'][0]
    print ("Get Token from posted data : " + token)
    if token != SLACKTOKEN:
        print ("Invalied Token, terminate process")
        return {
            "statusCode": 400,
            "headers": {
                "Content-Type:": "application/json"
            },
            "body": json.dumps({
                "response_type": "ephemeral",
                "text": "Invalid Token"
            })
        }
    retpost_url = params['response_url'][0]
    print ("Get response_url from posted data : " + retpost_url)
    
    str_command = "date;hostname;free -m;echo ''"

    print ("Create boto3 client for ssm")
    client = boto3.client(
        'ssm',
        region_name='ap-northeast-1',
    )

    comment=""
    print ("Into the for Loop with array of Instances")
    for str_instance in target_instances:
        print ("Excute command with ssm :" + str_instance)
        comment += command(client, str_instance, str_command)
    
    print ("add codesnipet on result")
    comment = "<@" + user + ">\r\n" + "```\r\n" + comment + "\r\n```"
    
    print ("return result : \r\n" + comment)
    print ("Making Object for posting to slack")
    
    obj_slack = {
        "response_type": "in_channel",
        "text": comment
    }
    requests.post(retpost_url, data=json.dumps(obj_slack))
    
    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": json.dumps(obj_slack)
    }

Slack 설정

slack slash command 어플리케이션이 이미 등록되어 있다고 가정하고, slash command에서 새로운 request를 작성한다.

  • command 를 /free 로 지정
  • URL은 API Gateway에서 확인한 Invoke URL을 지정
  • Method는 Post
  • token은 메모하여 Lambda코드에 삽입
  • 그외에 적당한 내용을 지정하여 저장

최종확인

slack에서 /free 를 입력하여 지정한 ec2의 free 결과가 표시되는 것을 확인한다. 실행이 잘 안될 경우엔 cloudwatch logs를 확인하자.

  • slash command의 timeout이 3초이기 때문에 여러대의 ec2에서 free -m 을 실행한 결과가 timeout되어 버린다. 어떻게 해결은 했는데 기억이.... 기억나는 대로 추가.
 

댓글

이 블로그의 인기 게시물

CISCO 2960s 초기화 후 기본 설정

curl 명령어 옵션

맥북 카라비너 영어/한글/일본어 전환하기