안녕하세요 여러분. 저는 네이선 클라크입니다. JMP를 22년째 사용해 왔고, IDEXX 연구소에서 근무하고 있습니다. 오늘 공동 발표자인 세이지 달링과 함께 비밀 관리에 대한 발표를 하겠습니다.
안녕하세요. 저는 세이지입니다. IDEXX에서 네이선과 함께 일하고 있습니다. 저는 여기서 수석 분석 엔지니어로 일하고 있으며, 오늘 여러분께 비밀에 대해 이야기해 드리겠습니다.
좋습니다. 그럼 비밀이 무엇인지 잠깐 이야기해 볼까요? 일반적으로, 적어도 코드 관점에서 비밀은 코드 작동에 필요한 일종의 자격 증명으로, 다른 사람들이 알면 안 되는 정보입니다. 컴퓨터에 로그인할 때 사용하는 비밀번호와 매우 유사합니다. 자주 사용해야 하지만, 다른 사람에게 알려줘서는 안 됩니다.
비밀은 다양한 플랫폼에서 이러한 자격 증명이 외부에 공개된 후에는 볼 수 없도록 하는 방식으로 개발된 방식입니다. 따라서 백그라운드 작업에서 훨씬 더 안전하게 사용할 수 있습니다. JMP에는 이러한 기능이 기본적으로 내장되어 있지 않습니다. 하지만 코드와 백그라운드 작업, 또는 JSL에서 숨겨진 작업을 더 많이 하게 되면서, 다른 사람들과 작업 내용을 공유하고, 실수로 다른 사람에게 왕국의 열쇠를 넘겨주지 않고도 다양한 작업에 접근할 수 있도록 이러한 기능이 필요하게 되었습니다.
얼마 전 JMP 지원팀과 이야기를 나누던 중, Evan McCorkle이 쓴 작은 코드를 접하게 되었는데, 그는 비밀을 가릴 수 있는 방법으로 이 코드를 작성했고, 지금 보시는 것처럼 스크립트를 암호화한 다음 사용할 수 있도록 했습니다.
기본적으로 사용하는 것은 비밀을 포함하는 하나의 함수이지만, 이 암호화된 코드 내의 모든 함수에 포함되어 있지만 다른 누구도 그것이 무엇인지 알 수 없는 보조 비밀이나 액세스 문구가 필요합니다. 그들이 비밀 A가 호출하려는 함수라는 것을 알고 있더라도, 이 문구가 무엇인지 알지 못하면 이러한 비밀에 직접 액세스할 수 없습니다. 이것이 암호화되면 이제 비밀 스크립트로 포함할 수 있으며, 그러면 알지 못하는 사이에 이러한 정보에 실제로 접근할 수 있습니다. 지금까지 JMP 지원팀과 이야기했을 때, 그들은 노력했음에도 불구하고 테스트 중에 비밀을 노출하는 방법을 찾지 못했습니다. 제가 작업해 온 것들로도 저도 할 수 없었습니다. 비밀을 안전하게 저장하면서도 사람들이 다양한 코드 활동을 할 수 있도록 허용하는 방법을 구축하기 위한 아주 좋은 프레임워크처럼 보입니다.
오늘은 두 가지 예를 들어보겠습니다. Snowflake에 이 기능을 어떻게 구현했는지 예를 들어보겠습니다. 제가 여기에 올린 것은, 죄송하지만 Snowflake 연결 템플릿입니다. 기본적으로 제가 작성한 함수에 필요한 모든 기능을 숨겨둔 것입니다.
여기서는 조금 더 크게 만들어 보겠습니다. get_secrets 함수에는 비밀 정보가 저장되는 위치가 있습니다. 제 경우에는 현재 설정된 Snowflake 설정에 접근하기 위해 사용자 이름과 비밀번호만 필요합니다. 이 비밀번호 배열은 비교적 쉽게 사용할 수 있습니다.
하지만 이들을 활용할 수 있는 다른 지원 기능도 있습니다. 첫 번째 기능은 데이터베이스에 실제 연결을 생성하고 새 데이터 커넥터를 반환합니다. 이는 문자열로, 사용자가 직접 입력할 수 있습니다. 데이터 커넥터가 있으면 회사와 관련된 모든 부분에 연결됩니다. 필요한 것은 Snowflake 드라이버만 설치되어 있으면 됩니다. Snowflake 웹사이트에서 컴퓨터에 Snowflake 드라이버를 설치할 때 드라이버 이름이 사용됩니다. 이렇게 하면 ODBC 연결을 만들 수 있습니다. 하지만 데이터베이스는 회사와 관련된 것입니다. 회사 서버는 Snowflake 등에 연결되어 있습니다. 그런 다음 비밀번호는 여기에 있는 다른 배열에서 가져옵니다. 비밀번호를 입력하면 연결할 수 있는 다른 부분이 여기에 있습니다.
제가 만든 마지막 함수는 한 단계 더 발전된 것입니다. 이 함수는 실행하려는 쿼리 문자열을 받아서 모든 연결을 설정하고 이 함수에서 쿼리를 실행합니다. 그러면 해당 테이블에서 생성되는 모든 테이블 스크립트를 제거합니다. 이 기능이 왜 유용한지는 예제를 설명할 때 설명하겠습니다. 기본적으로 이는 자격 증명이 실수로 공유되거나 노출되는 것을 방지하기 위한 또 다른 보호 계층입니다.
이제 정말 간단한 예를 들어보겠습니다. 첫 번째 예에서는 기본적으로 순수한 원시 쿼리를 수행하는 것이고, 사용자 지정 SQL을 수행하고 쿼리의 문자열 버전을 삽입합니다. 이것을 실행하면 Snowflake에서 테이블을 가져옵니다. Big Class와 매우 유사합니다. Snowflake에 복사본을 업로드했습니다. 이렇게 하면 원하는 대로 테이블이 제공됩니다. 여기에는 몇 가지 소스 정보가 포함됩니다. 좋을 수 있습니다. 이렇게 하면 예상대로 사용자 이름과 비밀번호가 마스킹된다는 것을 알았습니다. 이 작업을 여러 가지 방법으로 시도해 본 결과, 우연이든 아니든 비밀번호는 노출되지 않았지만 사용자 ID는 노출된 몇 가지 예가 있었습니다. 이러한 자격 증명을 얼마나 엄격하게 모니터링해야 하는지에 따라 이러한 정보를 제거하는 추가 기능을 만들었습니다.
여기 이 섹션을 주석 처리하고 지금 실행하면, 이 다른 함수로 새 테이블을 만들고, 이 함수를 쿼리로 입력하면 똑같은 결과가 나옵니다. 다만 이제 테이블에는 이러한 테이블 스크립트가 하나도 없습니다. 좋습니다. 작동 방식을 더 자세히 설명하자면, 예를 들어 이것을 삭제하고 이 별 그래프와 모든 열을 선택하려면 이제 이 함수가 작동하여 모든 열을 가져와야 합니다. 필터링 기능을 추가하려는 경우에도 마찬가지입니다. 여기에서 할 수 있습니다. 이러한 쿼리를 수행할 때 표준 SQL 언어와 동일하게 작동합니다. 문자열을 여기에 전달하고 스크럽 데이터 테이블을 가져옵니다. 비교적 간단한 예입니다. 이제 이 함수를 함수 계층화와 함께 사용하는 방법에 대한 더 복잡한 버전을 가지고 있는 Sage에 이 함수를 전달하고 싶습니다. 이제 Sage에 전달하겠습니다.
Fox Drive는 정보를 저장할 수 있는 온라인 폴더 저장 공간입니다. 저희는 이 기능을 다양한 용도로 활용하고 있는데, 이 때문에 Box에서 로컬로 파일을 가져오려면 Box에서 어떻게 인증해야 하는지 알아보고 싶었습니다. 이를 위해서는 Box Developers를 통해 인증할 수 있는 앱을 만들어야 합니다. 이렇게 하려면 앱에서 JWT(JSON 웹 토큰)를 제공해야 하는데, 이 JSON 웹 토큰 파이프라인을 통해 실제로 Box에 액세스하는 데 사용할 수 있는 액세스 토큰을 얻을 수 있습니다. JSON이나 JSON 웹 토큰, JWT를 사용해 본 적이 없어서 상황이 조금 더 복잡했습니다. 결국 JWT를 구현해야 했습니다.
네이선이 설명했듯이, 이건 제 secrets.jsl 파일의 오른쪽에 있는 예시입니다. 지금은 암호화되어 있지 않으므로 내부 구조를 확인할 수 있습니다. 제 파일은 get secrets로 시작하거나, get secrets 함수를 가지고 있습니다. 여기에 제 JWT 정보가 모두 들어갑니다. JWT에는 클라이언트 ID, 클라이언트 시크릿, 그리고 해당 애플리케이션에 고유한 정보 등이 포함되어 있습니다. 이 정보들을 연관 배열에 넣어서 나중에 가져올 시크릿으로 만들었습니다. 그런 다음 각 항목에 접근하기 위해 클라이언트 ID부터 시작하여 연관 배열 내의 항목들에 접근하는 다른 함수들을 만들었습니다.
이 중 하나만 보여드리겠습니다. 모든 것을 다 살펴보면 연관 배열의 모든 부분을 보게 되어 지루할 테니까요. 이 예제는 클라이언트 ID만 가져오는 것입니다. 이 안에서 비밀을 사용하여 비밀을 가져오는데, 비밀은 제 Box 액세스 키이고, 이를 통해 클라이언트 ID를 얻습니다. 다시 한번 말씀드리지만, 이 함수는 암호화되어 있기 때문에 모든 것을 비밀로 유지합니다.
조금 다른 점은 get box JWT 토큰과 관련이 있다는 것입니다. JWT는 기본적으로 서명 구성 요소가 필요한 새 액세스 토큰을 얻기 위해 어설션이 필요하기 때문에 약간 다른 기술이 필요합니다. 서명 구성 요소이기 때문에 실제로는 민감한 자료로 간주됩니다. 내 secrets.jsl에는 Box에서 해당 정보를 가져오기 위해 조금 더 자세히 처리하는 함수가 포함되어 있습니다. 이 경우, 내 JWT 함수는... 더 쉽게 볼 수 있도록 이것을 래핑합니다. 내 JWT 함수는 액세스 토큰을 얻기 위해 보낼 노력을 얻기 위해 Box로 해당 어설션을 생성합니다. 그러기 위해 위에서 내 비밀에 대해 가지고 있는 명시적 정보, 즉 get box 엔터프라이즈 ID, get box 클라이언트 ID, box 공개 키, 개인 키, 내 앱에 고유한 구문을 가져와야 합니다.
거기에서 몇 가지, 키가 누락된 경우와 같이 정말 중요한 문제 해결 방법을 찾았고, JWT 어설션을 실행하기 위해 Python을 사용해야 했습니다. 여기에는 secrets.jsl 파일 내에서 다른 언어를 사용하는 또 다른 예도 포함되는데, 이는 출력이 가능하도록 하기 위해 제가 조정해야 했던 부분이었습니다. 그래서 JWT 정보를 사용하는 스크립트가 아니라 secrets.jsl 파일에 암호화되어 있는 것입니다. 또한 이 JSL 내부에 Python이 통합된 것을 볼 수 있는 특별한 기회이기도 합니다. 정말 멋진 경험이었습니다.
그런 다음 해당 정보를 Python 스크립트로 보내면 해당 JWT에 대한 특정 서명을 가져오고, 거기서 자격 증명을 생성한 다음 해당 JWT 어설션을 반환하여 나중에 사용할 수 있습니다. 이제 JWT 어설션이 있으므로 액세스 토큰을 가져올 수 있습니다. 거기에서 기본적으로 Box 또는 위에서 본 Box JWT 토큰을 가져오고, 그런 다음 client_ID와 client_secret을 사용하여 해당 JWT_assertion을 가져오고, client_ID를 가져오고, client_secret을 가져오고, HTTP 요청을 사용하여 Box로 전송하여 토큰을 만듭니다. 그런 다음 새 액세스 토큰을 가져올 수 있습니다.
더 자세히 알아보고 싶어하는 개인을 위해 여기에 에어캐칭 기능도 있는데, 그러면 실제로 액세스 토큰을 받았는지 여부에 대한 정보를 보낸 다음 액세스 토큰을 사용자에게 반환합니다.
이건 어디에 사용되나요? 어떻게 사용되나요? 액세스 토큰 자체에 대해 더 자세히 이야기할 수 있는 흥미로운 주제가 있기 때문에 제 예시를 보여드리겠습니다. 이를 통합하기 위해 예시로 일반 폴더를 보여드리겠지만, 실제 코드에서는 몇 가지 입력값만 보여드리겠습니다.
제 경우에는 암호화된 Box 연결을 포함했는데, 비밀 파일 작업이 끝나면 이렇게 해야 하기 때문입니다. Box는 폴더 ID를 통해 위치를 지정하거나, 폴더별로 ID 코드를 부여하는 방식을 사용합니다. 이를 통해 검색할 파일을 찾을 폴더를 고유하게 식별할 수 있습니다. 여기에 고유 폴더 ID를 입력하면 됩니다. 저는 JMP 파일만 가져오고 있습니다. 하려는 작업에 따라 훨씬 더 복잡해질 수 있지만, 제 예시에서는 JMP 파일만 사용했습니다.
또한 여기에 재귀 깊이를 살펴볼 수 있는 매개변수를 포함했습니다.Box는 객체 지향적인 방식으로 작동하기 때문에 흥미롭습니다.폴더 ID가 있으면 해당 폴더 ID 내에서 ID를 가질 수 있으므로 폴더를 재귀적으로 검색해야 합니다.스크립트가 적합하다고 생각하는 만큼 많은 레이어를 사용할 수 있도록 허용합니다.이 경우 5개입니다.그런 다음 파일을 저장할 다운로드 위치가 있고 이름을 지정할 방법이 있습니다.이 예제에서 실제로 작동하는 방식과 보안을 위해 액세스 토큰과 관련된 몇 가지 복잡한 사항을 설명한 후 Box에서 일부 JMP 파일을 가져오는 예제를 보여드리겠습니다.
여기에는 JSL을 재귀적으로 검색하는 몇 가지 기능이 있습니다. 이러한 것들이나 Python 다운로드를 살펴보지는 않겠지만, 제가 할 일은 주요 Box 연결에 대해 이야기하는 것입니다. 이 경우, 모든 회사/사람에 대해 이것을 두는 가장 좋은 위치는 어디인지에 대한 측면에서 약간 흥미로울 수 있는 보안 측면에서 이야기했던 부분입니다. 이것을 두는 위치는 약간 다르고 보안 측면에서는 말하는 위치에 따라 다르지만 제 경우에는 여기서 멈췄습니다. 바로 시작하려면 이 주요 기능은 Box에서 정보를 가져와야 합니다. 그러기 위해서는 액세스 토큰을 가져와야 합니다. 액세스 토큰을 가져오는 것은 암호화된 secrets.jsl의 일부입니다. 이 경우, 하는 일은 이 액세스 토큰을 제공하는 것입니다. 이것은 이 JSL에 있는 변수입니다.
이 JSL에서는 액세스 토큰을 여기서 가져오므로, 583번째 줄에 print 문을 추가하면 액세스 토큰을 볼 수 있습니다. Box의 흥미로운 점, 혹은 좋은 점은 액세스 토큰이 만료된다는 것입니다. 나중에 누군가가 사용할 위험이 전혀 없습니다. 더 작아지지만, 이 액세스 토큰을 인쇄하거나 스크립트를 가져와서 실행하고 해당 위치에서 인쇄하는 경우 여전히 잠재적인 보안 위험이 있습니다.
이상적으로 또는 잠재적으로, 여기서 제가 한 것처럼 Box 액세스 토큰을 여기에 넣는 대신 테스트와 검색 모두인 인증 부분을 secret.jsl로 옮겨 암호화할 수 있습니다. 그러면 더 이상 액세스할 수 없고 다른 사람도 볼 수 없습니다. 약간 다른 사용 사례, 약간 다른 방식으로 원하는 대로 넣을 수 있습니다. 가장 안전한 방법은 Box 액세스 토큰을 secrets.jsl에 넣고 아무도 볼 수 없도록 암호화하는 것입니다. 하지만 이 경우에는 좋은 논의 주제이고, 제가 그대로 두었으므로 다음과 같습니다. 거기서부터 이야기해 보겠습니다.
그런 다음 Box 액세스 토큰을 받고 거기에서 실제로 Box 액세스 파일을 검색할 수 있습니다.이제 내가 누구인지 알려주는 인증 조각이 있고, 나를 들여보내야 합니다.제 경우에는 데모가 있고 데모에는 Box 드라이브에 있는 파일을 가져오는 예제가 있습니다.해당 파일 영역은 이와 같고 Secrets_JMP Discovery, File Examples_Secrets이고 가져올 JMP 테이블이 몇 개 있는데 이 위치에서 연결할 것입니다.이렇게 하려면 다음을 실행해야 합니다.그런 다음 비극적인 대기 음악을 재생합니다.때때로 스크립트를 실행할 때 발생하는 일이기 때문입니다.때때로 몇 초가 걸립니다.
인증, 내가 누군지, 네가 누군지 말해 줘. 여기 있어. 이게 내가 받은 파일이야. 내 원본 테이블이 보이는데, 그 상자 안에 있던 JMP 테이블 이름이고, 여기 연결된 테이블들이야. 그냥 재밌는 농담들이야.
Box 액세스 토큰을 JWT와 통합해서 이런 작업을 했습니다. 이제 Nathan에게 다시 전달하겠습니다.
Sage가 보여주고 제가 보여준 이 모든 것을 바탕으로, 실제로 어떻게 구현될 수 있을지, 그리고 이 작업을 완료한 후 저와 Sage뿐 아니라 더 많은 사람들이 이 작업을 할 수 있도록 하는 방법은 무엇일까요? 바로 GitHub에 올린 것입니다. GitHub의 모습은 다음과 같습니다. 저장소도 있고, 프레젠테이션과도 연결되어 있으며, 여기에 예제도 있습니다.
이제, 어떻게 구성하느냐에 따라, 여기에는 많은 옵션이 있습니다. 하지만 우리가 함께 모은 가장 중요한 것은, 여기 비밀 템플릿이 있습니다. 이것은 제가 이전에 정말 기본적인 값으로 보여드린 것입니다. 그리고 여기에 다양한 예가 있습니다. 이 예 안에는 기본적으로 세 개의 주요 파일이 있는데, 여기에 우리가 보여줄 템플릿이 있습니다. 여기에는 모든 정보가 들어 있습니다. 여기에 개인 또는 회사 정보를 입력할 수 있으며, 이것이 암호화를 위해 무엇을 하는지 알려줍니다. 이것을 안전하게 만드는 것은, 우리가 권장하는 것은 이 템플릿을 가져와서 저장소나 복제본에 이 파일을 저장하고 template을 raw라는 단어로 바꾸는 것입니다. 이렇게 하면 정말 중요한 모든 것이 숨겨집니다. 우리가 한 것은 이 gitignore에서 raw.jsl을 무시하는 것입니다. 이렇게 하면 작업할 수 있도록 로컬에 유지됩니다. 자격 증명이 있습니다. 자격 증명을 보관하세요. 그런 다음 원시 파일을 암호화하고 해당 파일의 암호화된 버전으로 업로드합니다.
이제 GitHub에 있는 유일한 것은 실행 가능한 암호화된 버전이어야 합니다. 각 폴더에는 용도에 맞는 문서가 있습니다. 기본 README 또는 문서에서 얼마나 공유할지는 이 정보를 어떻게 사용하는지 사람들에게 알리고 싶은지에 따라 달라집니다. Sage와 제가 작년에 발표한 Project Jab과 같은 것을 활용하거나 이미 사용하고 있다면, 이를 통해 추가 기능을 빌드하고 개별 저장소에서 파일을 가져올 수 있습니다. 필요한 작업을 수행하는 데 필요한 비밀 파일을 가져올 수 있는 방법입니다. 이는 가용성을 유지하면서 다양한 수준의 비밀을 유지하는 좋은 방법입니다.
세이지가 암시했듯이, 코드가 조금 더 복잡해지는 상황에 처하게 되면, 그 수준의 비밀을 유지하기 위해 암호화된 파일에 점점 더 많은 정보를 넣게 될 수 있습니다.
Sage가 템플릿에서 말했듯이, 여기에는 많은 작업을 수행하는 모든 함수가 있지만, 그녀가 예시로 들어갔을 때 매우 구체적인 액세스 토큰을 지적했습니다. 함수에서 정확히 어디에 있는지는 기억나지 않지만, 사람들이 볼 수 없도록 기본 예시에서 해당 함수를 추가하거나 템플릿화된 원시 파일에 추가한 다음 암호화하면 모두 숨겨집니다. 거쳐야 할 계층은 사용 사례와 수행하려는 작업에 따라 달라질 것이라고 생각합니다. Snowflake에서는 연결을 직접 사용하거나 간단히 테이블을 스크러빙할 수 있었기 때문에 비교적 쉬웠습니다. 따라서 마일리지가 다를 수 있으며 API 또는 그와 유사한 것과 같이 연결해야 할 사항이 다를 수 있습니다.
하지만 저는 그것이 여러분의 비밀을 살펴보고, 견고한 사이버 보안 관행을 유지하면서도 백그라운드 코딩을 개선할 수 있는 많은 계층을 제공할 수 있는 비교적 이해하기 쉽고 활용하기 쉬운 방법이라고 생각합니다.
오늘 이야기하고자 했던 내용은 이것으로 모두 마무리하겠습니다. 이 기회를 주신 JMP 관계자 여러분께 진심으로 감사드리고, 시청해 주신 모든 분들께도 감사드립니다.
전적으로 동의합니다. 비밀을 잘 지키고 계시길 바랍니다. 원하시면 올해 JMP Discovery에 오셔서 저희를 만나실 수 있습니다. 저희가 그 자리에 있을 테니까요.
네, 그렇게 하겠습니다. 감사합니다.