이야기 망치기;여러 Heroku 응용 프로그램에서 전송된 기밀을 회전시킵니다


소개하다.
나는 dev.to에 관한 감동적이고 도움이 되며 고무적인 문장/댓글을 많이 읽었다. 나는 오랫동안 뭔가를 돌려주고 싶었다.그 밖에 내 동료 한 명이 나에게 블로그 글을 쓰라고 재촉해 왔다. (고마워, 조나슨.) 그래서 나는 이 일과 그것이 어떻게 해결되었는지, 다른 사람들에게 도움이 되고, 재미있고, 깨우침이 될 것이라고 생각한다.
이것은 나의 첫 번째 게시물이다.영원히.어떤 피드백도 주저하지 마세요!

망쳤다
제목과 같이 나는git에 비밀을 제출했다.나는 이 비밀에 의지해서 로컬에서 코드를 실행해야만 했다. 왜냐하면 나는 내가 처리하고 있는 문제를 급히 해결하려고 했기 때문에, 나는 결국 모든 비밀을 잊어버렸다.그래서 나는 서류를 준비하고 제출 메시지를 써서 제출했고 그것들을 모두 GitHub로 보냈다. 비밀과 폭발을 포함해서!우리의 비밀은git 역사상 있다!

git 제출 기록 삭제
한 사람이 의외로 하나 이상의 비밀을 제출하고git 메모리 라이브러리로 전송할 때, 그들은 스트레스 속에서git 역사 기록에서 제출을 삭제하는 것을 고려할 수 있다.
Github에는 도구 interesting documentation을 사용하여 이 작업을 수행하는 방법에 대한 정보가 있지만 실제로 Github로 전송되는 경우에는 이 방법에 의존하지 않는 것이 좋습니다.

Warning: Once you have pushed a commit to GitHub, you should consider any data it contains to be compromised. If you committed a password, change it! If you committed a key, generate a new one.


그러니 우리는 그 방향으로 이 문제를 해결하려고 시도하지 말자.
BFG repo-cleaner
메서드
이것은 개인 저장소에서 발생하기 때문에 큰 문제이지만, 우리는 이 비밀을 즉시 취소하거나 삭제할 필요는 없지만, 어떤 사용자도 정지하지 않고 어떻게 교체할 것인가를 고려하는 데 시간이 좀 걸릴 수 있다.
공공 저장소에 있는 경우 이 기밀을 즉시 취소/삭제해야 할 가능성이 높다.
우리는 두 가지 문제를 해결해야 한다.
  • 은 우리의 모든 Heroku 프로그램에서 비밀을 회전시킨다.
  • 은 모든 사용자가 가동 중지 시간을 방지합니다.
  • 1) 해결 방안은 상당히 단도직입적이지만 2) 해결 방안은 더 많은 고려를 필요로 하고 용례에 따라 크게 다를 수 있다. 필요하다면.
    2)의 솔루션은 여러 기밀 처리에 대한 지원을 모듈에 추가하는 것입니다. 이 모듈은 권한을 부여합니다.목적과 모듈의 작업 방식 때문에, 우리는 새로운 비밀로 억지로 전환할 수 없다. 우리는 두 비밀을 모두 일정 시간 활성화시켜야만 낡은 비밀을 삭제할 수 있다.여러 개의 기밀에 대한 지원을 추가함으로써 우리는 모든 사용자가 잠길 위험을 피할 수 있다.
  • 모듈에 다중 기밀 지원 추가
  • 에서 Heroku 프로그램에 새로운 비밀을 추가하는 스크립트를 작성합니다.
  • 기존 기밀 확보 FOO 새 기밀 확보.
  • 이전 기밀을 사용하여 새 기밀 FOO_OLD 작성
  • 은 Heroku 프로그램의 오래된 비밀을 삭제할 준비가 되면 다른 스크립트를 작성합니다.

  • Heroku한테 비밀을 돌려요.
    비밀을 회전시키기 위해서, 나는 을 사용하여 비밀이 있는 프로그램을 찾고, 모든 응용 프로그램에서 실제적으로 비밀을 회전시킨다.
    이전에 Heroku CLI를 사용하지 않은 경우 먼저 설치하고 로그인해야 합니다.문서에는 Heroku's CLI 설명서가 있습니다.
    getting started
    번갈아 가며 프로그램 목록을 가져옵니다.
    첫째명령 heroku apps -A --json을 사용하여 모든 Heroku 응용 프로그램을 찾습니다.
  • -A 모든 팀으로 돌아가기
  • --json에서 결과를 json으로 되돌려줍니다.
  • const childProcess = require('child_process');
    const { promisify } = require('util');
    
    const exec = promisify(childProcess.exec);
    
    const { stdout: apps } = await exec('heroku apps -A --json');
    
    둘째필터 목록에서 업데이트하고 싶은 응용 프로그램 - 우리의 사례에서 생산 응용 프로그램만 업데이트하고 싶습니다.운영 애플리케이션에 대한 명명 규칙이 있으므로 다음과 같은 app.name 속성을 기반으로 애플리케이션을 필터링할 수 있습니다.
    const prodAppRegex = /^FOO$/;
    const isProdApp = (app) => app.name.test(prodAppRegex); // could also use a simple string comparison if fit your needs
    const prodApps = apps.filter(isProdApp);
    
    우리는 무대에 오르는 프로그램에서 같은 이름/키를 사용하여 같은 기밀을 가지고 있기 때문에 무대에 오르는 기밀을 덮어쓰지 않기 위해 이렇게 했습니다.만약 네가 단지 하나의 환경만 있다면, 너는 아마 이렇게 할 필요가 없을 것이다.
    셋째나머지 목록에서 환경 변수가 실제로 설정된 목록을 필터링합니다.만약 모든 응용 프로그램에서 환경 변수의 이름이 같지 않다면, 약간의 다른 방법을 찾아야 할 수도 있다.
    const appsWithSecret = []; // list of apps that has the environment variable(s) to rotate
    for (const app of JSON.parse(apps)) { // returned as a string
      const { name, ...otherPropsYouMightNeed } = app;
    
      const { stdout: config } = await exec(`heroku config -a ${name} --json`);
    
      const isMatch = ([key, value]) => key === '<env variable key>';
      // if any app could have multiple env variable matches
      // to rotate, you should use .filter instead
      const match = Object.entries(config).find((isMatch));
    
      if (!match) {
        continue;
      }
    
      appsWithSecret.push({ name, envVariable: match, otherPropsYouMightNeed });
    }
    

    응용 프로그램 목록에서 기밀 회전

    애플리케이션 기밀 유지
    앞에서 말한 바와 같이, 내가 이런 스크립트를 작성할 때, 나는 실행 기능을 포함하는 것을 좋아한다. 이 스크립트들은 실제 실행하기 전에 결과를 검증하기 위해 중요한 것을 삭제하거나 갱신하거나 만들 수 있다.
    우리는 모든 프로그램 이름과 설정 변수 키를 사용하여 설정 변수를 가져옵니다.
    async function getAppSecret(appName, configVar) {
      const { stdout } = await exec(`heroku config:get ${configVar} -a ${appName}`); // -a or --app
    
      // returns a string of the value
      return stdout;
    }
    
    실제로 appsWithSecrets에 애플리케이션 기밀이 저장되어 있으므로 이 작업을 건너뛰거나 appsWithSecrets의 필터링 섹션으로 관련 애플리케이션을 푸시하는 대신 수행할 수 있습니다.

    응용 프로그램의 비밀 업데이트
    마찬가지로, 우리는 모든 응용 프로그램 이름과 설정 변수 키를 사용하지만, 설정 변수의 새로운 값을 업데이트하려고 하는 것도 포함한다.
    async function setAppSecret(appName, configVar, newValue) {
      const { stdout: result } = await exec(`heroku config:set ${configVar}=${newValue} -a ${appName}`); // -a or --app
    
      // returns a string like:
      // Setting <configVar> and restarting ⬢ <appName>... done, <new app version>
      // <configVar>: newValue
      return result;
    }
    

    모든 애플리케이션을 새 암호로 업데이트
    const DRY_RUN = true; // set to false when you want to execute it
    const { NEW_VALUE } = process.env; // you can set this when running your script like: "NEW_VALUE=FOO node ./yourScript.js"
    
    for (const app of appsWithSecret) {
      const { name, envVariable } = app;
      const [key, secret] = envVariable;
    
    
      if (DRY_RUN) {
        const appSecret = await getAppSecret(name, key);
        // could verify "secret" === "appSecret"
        // console.log('is same secret?', appSecret === secret)
      } else {
        const resultOldKey = await setAppSecret(appName, `${key}_old`, secret);
        const resultNewKey = await setAppSecret(appName, key, NEW_SECRET);
      }
    }
    

    모든 응용 프로그램의 오래된 비밀 해제
    "새 키를 추가하는 것과 유사한 방법/코드를 사용했지만""구형""키를 찾기 위해 isMatch 함수를 약간 변경했습니다."
      const isMatch = ([key, value]) => key === '<env variable key>_old'; // we postfixed "_old" in previous steps when also adding new secrets in each app
    
    그런 다음 준비된 시점에 각 애플리케이션의 기존 비밀을 제거할 수 있습니다(다운타임 방지와 관련).
    async function unsetAppSecret(appName, configVar) {
      const { stdout: result } = await exec(`heroku config:unset ${configVar} -a ${appName}`);
    
      // returns a string like:
      // Unsetting <configVar and restarting ⬢ <appName>... done, <new app version>
      return result;
    }
    
    당신은 에서 완전한 코드 예시를 찾을 수 있습니다.
    this gist
    배달하다
  • 은git에서 무시하지 않은 파일 코드에 임시로 기밀을 저장하지 않습니다.인간의 실수가 일어날 수도 있고, 아주 짧은 시간 안에 모든 비밀을 잊어버릴 수도 있다.
  • 은 비밀 회전을 위해 모듈, 부품 등을 준비한다.비밀이 하나 누설됐기 때문에 그럴 필요는 없었으면 좋겠지만, 이럴 경우 긴 응용 프로그램에서 빠르게 번갈아 끼울 수 있는 것이 좋다.
  • 모듈의 목적에 따라 여러 개의 기밀을 사용하는 것에 대한 지원을 추가하여 교대 시 정지가 발생하지 않도록 하십시오.
  • 비밀을 교대하는 방법이 생겼을 때 왜 정기적으로 하지 않습니까? 예를 들어 반년, 매년 등등입니다.?
  • 은git 역사 기록을 삭제하는 것을 의외로 기밀을 제출하는 적당한 해결 방안으로 고려하지 않는다.
  • 원격 호스트로 전송, 전송 및 푸시 결정을 내리기 전에 로컬에서 변경 사항을 검토하십시오.만약 내가 이 점을 해낸다면, 나는 나의 코드에 여전히 비밀이 저장되어 있고, 재난을 피할 수 있다는 것을 알게 될 것이다.
  • 은 기밀을 어떻게 사용하는지, 그리고 응용 프로그램/서비스/모듈 간에 기밀을 어떻게 의존해서 권한을 부여하는지를 고려합니다.만약 네가 도처에서 같은 비밀을 사용하고 있다면, 그것은 이미 약간 냄새가 났을 것이다...
  • 좋은 웹페이지 즐겨찾기