[AWS] EC2 접속용 SSH 키페어 분실 또는 손상 시 키 재생성 방법

현재 운영 중인 EC2 인스턴스를 SSH로 접속하는 용도로 SSH Key-pair를 사용합니다. 서버에 public-key를 저장해놓고 private-key는 로컬에 보관하여 사용합니다. 일반적으로 PEM 키를 사용합니다.

사용 중인 맥북을 공장초기화하면서 로컬에 있던 개인키(private-key)가 안전하게 i-Cloud에 저장되어있을 것이라 생각했습니다. 생각대로 공장초기화 후 i-Cloud를 통해 개인키를 다운받았고 EC2 인스턴스를 SSH로 접속해봤습니다. 그런데 접속이 되질 않습니다.

Permission denied (publickey).

개인키 퍼미션도 600으로 낮춰놨고 아무런 문제가 없었지만 계속 저 메세지만 출력되었습니다. 끝내 i-Cloud로 복원된 개인키가 손상되었다는 결론을 내게 되었고 키페어를 새로 생성하기로 했습니다.

키 페어 새로 생성하여 적용하는 방법

1. 우선 SSH를 접속할 로컬 환경에서 키를 새로 생성한다. 아래 명령을 입력한뒤 엔터 연타

$ ssh-keyhen -m PEM

2. 생성된 개인키의 공개키(public-key)를 출력하여 복사한다.

$ ssh-keygen -y -f {개인키 파일 경로}

3. AWS EC2 콘솔 -> 해당 인스턴스 중지 -> 인스턴스 우클릭 -> Instance Settings -> Edit user data -> 아래 스크립트 입력

Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0

--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"

#cloud-config
cloud_final_modules:
- [users-groups, once]
users:
  - name: ec2-user
    ssh-authorized-keys: 
    - {위에서 복사한 공개키}

4. 저장 후 인스턴스 시작

5. SSH 접속 테스트

$ ssh -i {개인키 경로} ec2-user@{접속 호스트}

6. 잘 되면 성공. 이제 3번에서 저장했던 스크립트를 삭제해야한다. 저 스크립트는 EC2 서버에서 .ssh/authorized_keys 파일에 공개키를 넣어주는 역할이다. 즉, 한번 실행되고 나면 역할을 다하는데다 콘솔에 공개키를 포함한 스크립트가 존재하는 것은 보안상 리스크가 있기 때문에 삭제 해주는 것이 좋다. 인스턴스를 다시 중지한 후 3번 Edit user data 화면에서 저장한 스크립트를 삭제 -> 저장 후 인스턴스를 다시 시작한다.

7. 최종 접속 확인. 5번 접속 테스트를 다시 한번 해보고 접속이 잘된다면 키페이 교체는 완료된 것이다.

[React] AWS Amplify 환경 변수 추가 방법

React 프로덕트를 AWS Amplify를 이용해 배포 시 환경 변수를 통해 간편하게 개발과 운영 환경을 분기할 수 있습니다.

예를 들어 요청 API 도메인이 개발과 운영이 다른 경우 요청 도메인을 외부 변수로 빼서 관리를 해야합니다. 이를 기존에는 .env를 통해 처리했지만 Amplify에서는 환경 변수를 세팅할 수 있는 기능을 제공합니다.

AWS Amplify > 앱 설정 > 환경 변수 > REACT_APP_API_URL 변수명을 추가하고 해당하는 API URL을 넣어줍니다. 하나의 앱환경에 Git 브랜치 별로 구성되어있다면 대상 브랜치도 선택할 수 있습니다.

설정된 REACT_APP_API_URL 이라는 변수는 React 소스상에서 기존 .env 환경 변수 사용법과 동일하게 process.env.REACT_APP_API_URL로 설정 값을 사용할 수 있습니다.

단, 이미 배포된 상태에서 환경 변수를 추가하는 경우 적용되지 않고 재배포를 해야 추가/변경된 환경변수가 적용됩니다.

[Kotlin/Spring] JPA/QueryDSL KotlinDSL Gradle 설정 방법

Kotlin DSL 문법으로 QueryDSL을 Gradle로 설정하는 방법을 정리합니다.
아래 내용은 build.gradle.kts에서 JPA와 QueryDSL 관련 내용만 추려서 정리한 것입니다.

plugins {
    kotlin("plugin.jpa") version "1.4.10"
    kotlin("kapt") version "1.4.10"
}

dependencies {
  	implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("com.querydsl:querydsl-jpa")
    kapt("com.querydsl:querydsl-apt:4.2.2:jpa")
    annotationProcessor(group = "com.querydsl", name = "querydsl-apt", classifier = "jpa")
}

sourceSets["main"].withConvention(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::class){
    kotlin.srcDir("$buildDir/generated/source/kapt/main")
}

아래 링크에서 도움을 많이 받았습니다. 좀 더 상세한 정보가 있으니 참고해보시길 추천 합니다.
https://velog.io/@gosgjung/kotlin-DSL-gradle-QueryDSL-%EC%84%A4%EC%A0%95

[AWS] ElasticLoadBalancer(ELB) 적용된 ElasticBeansTalk(EB) Instance SSH 접속 방법

ElasticBeanstalk로 구성된 서비스에 https를 사용하려면 ELB를 구성하여 발급된 SSL인증서를 적용해야 합니다. 여기서 ELB는 인프라에 앞단에서 https(443 포트) 접근을 받아 ElasticBeanstalk(이하 EB)에 넘기는 역할을 합니다.

위 처럼 구성된 경우 EB 인스턴스의 SSH 접근이 EB public DNS를 통해 되지 않게 됩니다. 이 경우 EB에 해당하는 EC2 인스턴스의 Public IP 또는 Public DNS로 SSH 접속이 가능합니다. Public IP/Public DNS는 EC2 인스턴스 재시작 시 변경됩니다. IP가 변경되지 않도록 하려면 ElasticIP를 이용해 고정 IP를 할당받아야 합니다.

그 전에 EC2 Key-pair 생성(pem키 발급) 또는 등록이 필요하고 해당 EC2 인스턴스의 보안 그룹(SecurityGroup)에서 SSH 22번 포트 Inbound 설정이 필요합니다. 설정이 완료되었다면 아래와 같이 접근이 가능합니다.

$ ssh -i {개인키 경로} ec2-user@{EC2 PublicIP or PublicDNS}

[SpringBoot] Elastic Beanstalk Profile 변수 적용되지 않는 이슈

개인 프로젝트를 위해 Kotlin + Spring boot + AWS 환경에서 개발을 진행하고 있는데 삽질이 이만저만이 아니어서 계속 포스팅이 이어질 것 같습니다.

Elastic Beanstalk 줄여서 EB라 하겠습니다. EB에서 개발과 운영 환경 분기를 위해 환경변수를 세팅할 수 있습니다. 제 경우에는 application.properties를 이용해 application-dev.properties와 application-prod.properties 각 별도 파일로 분리시켰습니다. application.properties 정의를 하고 환경변수에 해당 환경에 대한 키워드를 대입하면 손쉽게(?) 환경 분기를 시킬 수 있습니다.

그런데 안되서 어제 하루 종일 삽을 펐습니다. 문제는 EB에서 SPRING_PROFILES_ACTIVE 변수를 dev로 지정했음에 불구하고 배포 시 이를 읽지 못하고 default profile이 적용되는 문제였습니다.

하루 반나절만에 해결이 되었습니다. 문제는 환경 변수 키워드가 원인이었고 SPRING_PROFILES_ACTIVE가 아닌 spring.profiles.active로 환경변수를 지정해줘야 했습니다.

맥북 터치바 사라진 ESC 키 살리는 방법

언제부턴가 사용중인 맥북의 터치바에 ESC 키가 나타나지 않고 있었다. OS 업데이트 이후 현상인가라고 생각했지만 쓰면 쓸수록 ESC 없는 키보드는 적응이 안됐다.

잠시 검색해보니 간단한 방법으로 살릴 수 있었다. 터치바 프로세스를 죽이면 죽인 프로세스가 다시 올라오면서 사라졌던 ESC 키가 돌아온다.

터미널을 실행 시키고 아래 명령을 입력 후 엔터, 맥북 계정의 비밀번호를 입력하면 된다.

$ sudo pkill TouchBarServer

[AWS] Amazon Linux AMI에서 PHP 7.x 설치

아마존 리눅스에서 PHP 7.x 버전 설치하는 방법을 소개합니다. EC2 인스턴스 생성 직후 $ sudo yum info php* 로 패키지를 조회 해보면 php 5.4 버전 기준의 패키지만 검색됩니다. 아래 단계를 진행하시면 php7 버전 설치가 가능합니다.

진행 방법

// php 최신 버전 조회
$ sudo amazon-linux-extras | grep php
// php 7.4 레포지토리 설치 (작성일 기준에서 최신버전은 php7.4)
$ sudo amazon-linux-extras install php7.4
// php 7.4 패키지 활성 (기존 설치된 버전이 있다면 disable 명령 후 진행)
$ sudo amazon-linux-extras enable php7.4
// php 모듈 설치
$ sudo yum install  php-cli php-common php-gd php-mbstring  php-mysqlnd php-pdo php-fpm php-xml php-opcache php-zip php-bcmath
// php 버전 확인
$ php -v

* 이 내용은 https://www.lesstif.com/lpt/amazon-linux-ami-php-7-3-77955353.html 을 바탕으로 재작성하였습니다.

[Chrome] input 자동 완성(autocomplete) 비활성 방법

크롬 브라우저에서 자동 완성을 비활성 시키는 방법을 정리합니다. 해결 방법은 의외로 간단했지만 검색해보면 각기 다른 해결 방법이 소개되어 있어 오히려 혼란스러웠던 것 같습니다. 다른 타입은 테스트해보지 않았지만 input type=”text” 에서는 적용되는 것을 확인했습니다.

<input type="text" name="userName" autocomplete="no" />

위 예제에서 중요한 부분은 autocomplete=”no” 입니다. 다른 구글링 내용들을 보면 autocomplete=”off”를 사용해보라는 언급들이 있지만 크롬에서는 동작하지 않고 자동 완성 목록을 뿌려줍니다. 약간의 발상 전환을 해서 제시되지 않은 키워드들을 넣어보았습니다. 결과는 성공이었습니다. 즉, off가 아닌 다른 키워드를 입력하면 됩니다. 일종의 핵같은 방법이라고 볼 수도 있습니다. 예제에서는 no라고 명시했습니다. 이 또한 크롬 브라우저 업데이트가 된다면 어떻게 될지는 모르니 주의가 필요합니다.

해당 테스트는 Chrome 81.0.4044.122(공식 빌드) (64비트) 버전에서 진행되었습니다.

jQuery Selector로 iframe 제어하는 방법

jQuery를 이용해 iframe 내에서 부모 document 그리고 부모 document 내에 존재하는 다른 iframe에 접근하는 방법을 우선 정리해보고 이를 응용할 수 있는 예시를 한 번 더 정리해보겠습니다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Code Sample</title>
  </head>
  <body>
    <div id="content">Content Sample</div>
    
    <iframe id="frameA" src="[frameA]"></iframe>
    <iframe id="frameB" src="[frameB]"></iframe>
  </body>
</html>

iframe 내에서 부모 document 접근 방법

<script>
  // 부모 도큐멘트에서 #content 엘리먼트를 참조하여 hide() 처리
  var parentDocumentContent = $("#content", parent.document);
  parentDocumentContent.hide();
</script>

iframe 내에서 부모 document의 다른 iframe 접근

<script>
  // 부모 도큐멘트의 #frameB iframe 내 #frameBContent 엘리먼트를 참조하여 hide() 처리
  var frameBContent = $("#frameBContent", parent.frames["frameB"].document);
  frameBContent.hide();
</script>

응용 : iframe 내 document의 height 값을 구해 iframe의 height 값을 세팅

<script>
// This iframe name is "contentFrame"

$(document).ready(function(){
  
  // 현재 document를 불러오는 iframe의 selector를 정의한다.
  var thisFrame = $("#contentFrame", parent.document);
  
  // 현재 document의 height 값을 정의한다.
  var documentHeight = $(document).height();

  // 부모 document에서 iframe을 thisFrame에 정의된 selector로 참조하여 iframe의 height값을 css로 설정한다.
  thisFrame.css("height", documentHeight + "px");
});
</script>

jQuery를 버리고 Vanilla JS로 옮겨타고 싶지만 제 자신이 너무 오랜 시간 jQuery에 익숙해진 듯 합니다.

그래서 다음 포스팅에서는 제가 주로 사용하는 jQuery 문법들을 정리하고 이에 대응하는 Vanilla JS 표현식을 알아보도록 하겠습니다.

[MacOS] 카탈리나(Catalina) 권한 승인 이슈

MacOS 카탈리나 업데이트 이후 MAMP와 같이 백단에서 시스템 디렉토리를 엑세스하는 앱에서 경로 접근 불가 이슈가 발생합니다.

이 엄격해진 보안이 시스템 디렉토리(/Desktop, /Applications, /Download, /Documents)의 접근을 제한시킵니다.

해결 방법은 위에 언급된 디렉토리 내에 접근 경로가 존재하는 경우 /Users/{사용자계정}/ 경로에 디렉토리를 새로 생성하여 위치를 옮깁니다. 사용자 계정의 루트 디렉토리(~/)는 위 제약사항에 해당되지 않습니다.