이야기 망치기;여러 Heroku 응용 프로그램에서 전송된 기밀을 회전시킵니다
17977 단어 automationherokujavascriptsecurity
소개하다.
나는 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
메서드
이것은 개인 저장소에서 발생하기 때문에 큰 문제이지만, 우리는 이 비밀을 즉시 취소하거나 삭제할 필요는 없지만, 어떤 사용자도 정지하지 않고 어떻게 교체할 것인가를 고려하는 데 시간이 좀 걸릴 수 있다.
공공 저장소에 있는 경우 이 기밀을 즉시 취소/삭제해야 할 가능성이 높다.
우리는 두 가지 문제를 해결해야 한다.
2)의 솔루션은 여러 기밀 처리에 대한 지원을 모듈에 추가하는 것입니다. 이 모듈은 권한을 부여합니다.목적과 모듈의 작업 방식 때문에, 우리는 새로운 비밀로 억지로 전환할 수 없다. 우리는 두 비밀을 모두 일정 시간 활성화시켜야만 낡은 비밀을 삭제할 수 있다.여러 개의 기밀에 대한 지원을 추가함으로써 우리는 모든 사용자가 잠길 위험을 피할 수 있다.
FOO
새 기밀 확보.FOO_OLD
작성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
배달하다
Reference
이 문제에 관하여(이야기 망치기;여러 Heroku 응용 프로그램에서 전송된 기밀을 회전시킵니다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/hilleer/fuck-up-story-rotate-committed-secret-s-on-multiple-heroku-apps-26l텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)