EnvFolio 1.0: เก็บ secret ของคุณให้พ้นสายตา

store เดียว vars file หนึ่งไฟล์ต่อโปรเจกต์ และไฟล์ export ที่เข้ารหัสสำหรับเครื่องที่ไม่มี store

EnvFolio เก็บ text และ secret ของคุณไว้ในที่เดียว และส่งให้คำสั่งก็ต่อเมื่อคุณสั่งเท่านั้น ตอนนี้เวอร์ชัน 1.0 ออกแล้ว

ขอถามหน่อย: ตอนนี้ secret ของแอปพลิเคชันคุณอยู่ที่ไหน? อยู่ในไฟล์ .env อยู่ในบรรทัด export ใน ~/.bashrc อยู่ใน shell history ตั้งแต่วันที่คุณแปะ token ลงใน curl ทั้งหมดนั้นเป็น plain text และอยู่บนทุกเครื่องที่คุณใช้ทำงาน

แถมมันยังเดินทางไปด้วย คุณทำงานใน container ใน cloud dev environment และข้าง ๆ AI agent ที่อ่านทุกไฟล์ในโปรเจกต์ secret ที่เป็น plain text จะตามไฟล์ของคุณไปทุกที่

▶
อยากดูแบบวิดีโอแทน? เนื้อหาเดียวกันมีเป็น Short ความยาว 2 นาทีครึ่ง: ดูได้ที่นี่

รู้จัก EnvFolio

EnvFolio คือเครื่องมือ command-line ขนาดเล็กชื่อ folio ที่เก็บ text และ secret ของคุณไว้ใน store เดียว แล้วส่งให้โปรแกรมโดยตรงในรูปของ environment variable และเฉพาะเมื่อคุณสั่งเท่านั้น นี่คือแนวคิดทั้งหมด:

ไม่อยู่บน command line ไม่อยู่ในไฟล์ ไม่ขึ้นบนหน้าจอ

ตั้งแต่ 1.0 เป็นต้นไป คำสั่ง option และรูปแบบไฟล์ (store, vars file, export และ backup) ถือว่า stable แล้ว การเปลี่ยนแปลงใดที่ทำให้สิ่งเหล่านี้ใช้ไม่ได้ จะมาพร้อมกับ major version ใหม่

สร้างบน pass

EnvFolio ไม่ได้ประดิษฐ์ vault ขึ้นมาเอง แต่สร้างบน pass ซึ่งเป็น password manager มาตรฐานของ Unix secret ของคุณถูกเข้ารหัสด้วย GPG key ของคุณเอง และทุกการเปลี่ยนแปลงจะถูกบันทึกใน git history ของ store ตัว store อยู่ที่ ~/.folio แยกจาก ~/.password-store ของคุณ แต่มีโครงสร้างเหมือนกัน คุณจึงยังใช้ pass ธรรมดาเปิดทุก secret ในนั้นได้:

PASSWORD_STORE_DIR=~/.folio pass show gh/token

Text และ secret

EnvFolio เก็บ item สองแบบ text เช่นชื่อผู้ใช้หรือ host จะเก็บแบบไม่เข้ารหัส แต่ลงลายเซ็นด้วย key ของคุณ คุณจึงรู้ได้ถ้ามีใครแก้มัน ส่วน secret ถูกเข้ารหัสอย่างที่ควรจะเป็น ทั้งสองแบบไม่มีทางปนกัน: ทุกคำสั่งที่แตะ secret จะต้องระบุคำว่า secret ไว้ชัด ๆ และ secret จะไม่ถูกรับเป็น argument เด็ดขาด

folio text insert -t "demo@example.com" gh/user
folio secret insert gh/token

folio ls แสดงทั้งสองแบบเคียงกัน:

EnvFolio
$ folio ls
EnvFolio Store
├── aws
│   └── 📄region
├── db
│   ├── 🔑pass
│   └── 📄user
├── gh
│   ├── 🔑token
│   └── 📄user
└── git
    └── 📄user_name

ส่งให้คำสั่ง

เวลาจะใช้ item ให้รันคำสั่งของคุณผ่าน folio exec แต่ละ item จะกลายเป็น environment variable สำหรับคำสั่งนั้นคำสั่งเดียว ตั้งชื่อตาม path ของมัน: / กลายเป็น _ แล้วแปลงเป็นตัวพิมพ์ใหญ่ ดังนั้น gh/token จึงกลายเป็น GH_TOKEN อยากได้ชื่ออื่น? ใส่ไว้ข้างหน้า: GITHUB_TOKEN=gh/token

text จะถูกโหลดโดยปริยาย ส่วน secret จะมาด้วยก็ต่อเมื่อใส่ -s (--secrets) ทุก item จะถูกตรวจและอ่านก่อนคำสั่งเริ่มทำงาน ถ้ามีตัวไหนพลาด คำสั่งจะไม่ถูกรัน echo ด้านล่างมีไว้แค่พิสูจน์ว่าค่ามาถึงแล้ว คำสั่งจริงก็แค่ใช้มันไป

EnvFolio
# Use an item as a variable
$ folio exec -s gh/token -- sh -c 'echo ${GH_TOKEN}'
ghp_DEMO0000fake0000token
# Or pick its name
$ folio exec -s GITHUB_TOKEN=gh/token -- sh -c 'echo ${GITHUB_TOKEN}'
ghp_DEMO0000fake0000token

ระบุชื่อโฟลเดอร์ แล้วทุก item ในโฟลเดอร์นั้นจะมาด้วย ไม่แน่ใจว่าจะได้อะไรบ้าง? ใส่ --names: มันจะแสดงว่า variable ไหนได้ค่าจาก item ไหน แล้วหยุด ไม่มีการอ่านหรือถอดรหัสอะไร และคำสั่งก็จะไม่ถูกรัน

EnvFolio
# Use every items in a folder
$ folio exec -s gh -- sh -c 'env | grep GH_'
GH_TOKEN=ghp_DEMO0000fake0000token
GH_USER=demo@example.com

# Use `--names` to show which var get value from which item
# Note that `--names` will stop the command from running -- make this a dryrun.
$ folio exec --names -s gh -- gh repo list
GH_TOKEN <- 🔑gh/token
GH_USER  <- 📄gh/user

ต้องการ item ไว้ใช้ทั้ง session แทนที่จะเป็นคำสั่งเดียว? folio shell ทำแบบเดียวกัน แต่เปิด shell ของคุณขึ้นมา มันจะพิมพ์ชื่อที่โหลด แต่ไม่พิมพ์ค่าเด็ดขาด

เขียนไว้ครั้งเดียว: vars file

พิมพ์ชื่อ item ทุกครั้งก็น่าเบื่อ สำหรับโปรเจกต์หนึ่ง ให้เขียนไว้ครั้งเดียวว่าคำสั่งของมันต้องใช้อะไร และแต่ละค่ามาจากไหน ในไฟล์ vars:

app.vars · commit ไปพร้อมกับโค้ด
GH_TOKEN=@{gh/token}
DB_URL=pg://@{db/user}:@{db/pass}@${DB_HOST}/app
LOG_LEVEL=info
@{name}text หรือ secret จาก store
${NAME}จาก environment ของคุณ
…:-fallbackถ้าไม่ได้ตั้งค่าหรือไม่มีอยู่: @{gh/token:-none}
@{folder/*}ทุก item ในโฟลเดอร์
LOG_LEVEL=infoค่าคงที่

ไฟล์นี้เก็บว่าค่าอยู่ที่ไหน ไม่ได้เก็บตัวค่า จึง commit ไปพร้อมโค้ดได้ ไม่มีอะไรในไฟล์ถูกรันเลย: EnvFolio อ่านมันทีละตัวอักษรและไม่เคยส่งให้ shell ดังนั้น $(…) และ backtick จะถูกปฏิเสธ folio vars check ตรวจไฟล์ได้โดยไม่ต้องมี store เช่นใน CI จากนั้นบรรทัดเดียวก็รันคำสั่งของโปรเจกต์ได้ ในตัวอย่างนี้ deploy.sh เป็นตัวแทนที่รายงานว่าได้รับอะไรมาบ้างโดยไม่แสดง secret:

EnvFolio
$ folio exec -s --vars app.vars -- deploy.sh
==| Super Cool App -- Deployment |==
Parameter check:
 GH_TOKEN : ✅ Given
 DB_URL   : ✅ pg://app:###@12.34.56.7/app
 LOG_LEVEL: info
Deployment will now start ...
...
--| Deploying is completed |--

พาไปได้ทุกที่

มาถึงส่วนที่เป็นจุดเริ่มต้นของทั้งหมด: การรันคำสั่งนั้นบนเครื่องที่ไม่มี store เช่น remote server อย่าง CI/CD server folio export จะแพ็กเฉพาะ item ที่ vars file ระบุไว้ลงในไฟล์เข้ารหัสไฟล์เดียว มันสร้าง key ใหม่สำหรับ export ครั้งนี้เท่านั้น key ของ store คุณจึงไม่เคยออกจากเครื่อง และมันล็อกไฟล์เสมอ: ด้วย passphrase ที่คุณเลือก หรือด้วย --to ไปยัง public key ของเครื่องปลายทาง

💻 laptop ของคุณ
$ folio export -s --vars app.vars -o app.folio
✓ Items: 3 (texts: 1, secrets: 2)
✓ File: app.folio

ที่อีกฝั่ง folio exec --from จะรันคำสั่งด้วย item จากไฟล์นั้น ไม่ต้องมี store และไม่มีการสร้าง store ขึ้นมา ไฟล์จะถูกแตกลงในโฟลเดอร์ชั่วคราวส่วนตัว และโฟลเดอร์นั้นจะถูกลบก่อนคำสั่งเริ่มทำงาน: ไม่มีอะไรหลงเหลือ

☁️ remote server เช่น CI/CD — ไม่มี store
$ folio exec -s --from app.folio --vars app.vars -- deploy.sh
==| Super Cool App -- Deployment |==
Parameter check:
 GH_TOKEN : ✅ Given
 DB_URL   : ✅ pg://app:###@12.34.56.7/app
 LOG_LEVEL: info
Deployment will now start ...
...
--| Deploying is completed |--

แล้วอะไรเดินทางแบบเปิดเผยได้บ้าง? vars file ไม่มี secret และไฟล์ export ถูกล็อกไว้: ทั้งคู่วางไว้ข้างโค้ดหรือบน server ได้ สิ่งเดียวที่ต้องเก็บไว้กับตัวคือสิ่งที่ใช้เปิดไฟล์: passphrase ที่ต้องอยู่นอก repository และไม่เคยอยู่ข้างไฟล์ หรือถ้าใช้ --to ก็คือ secret key บนเครื่องปลายทาง ซึ่งไม่เคยเดินทางไปไหนเลย secret ของคุณไปถึงเครื่องที่คุณไม่ได้เป็นเจ้าของ โดยที่ผู้ให้บริการเครื่องนั้นไม่เคยแตะต้องมัน

ทำไมถึงไว้ใจได้

EnvFolio เป็น bash script ไฟล์เดียว และรันบน bash 3.2 ที่มากับ macOS ได้ ต้องการแค่ pass, gpg และ git แทบไม่มีอะไรมากกว่านั้น คุณอ่านได้ทุกบรรทัด และเห็นด้วยตัวเองว่าไม่มี secret ไหนไปในที่ที่ไม่ควรไป

folio backup บันทึกทั้ง store รวมถึง key (ยังอยู่ภายใต้ passphrase ของมัน) ลงในไฟล์เดียว และ folio restore นำกลับมาบนเครื่องใหม่ และถ้าวันหนึ่งคุณเลิกใช้ EnvFolio ก็ไม่มีอะไรถูกล็อกไว้: secret ของคุณเป็น entry ของ pass ธรรมดา และ text เป็นไฟล์ธรรมดา

ติดตั้ง

ดาวน์โหลด folio จาก release ล่าสุด แล้วตรวจกับ SHA256SUMS มันคือ script ที่เห็น secret ของคุณ จึงต้องระวังเรื่อง permission: ใครที่แก้มันได้ก็อ่าน secret ได้ ทำให้มัน executable แต่ให้คุณคนเดียวที่เขียนได้ และวางไว้ใน PATH ในโฟลเดอร์ที่มีแค่คุณที่เขียนได้:

sha256sum -c SHA256SUMS     # shasum -a 256 -c SHA256SUMS on macOS
chmod 755 folio              # everyone may run it, only you may change it
mkdir -p ~/.local/bin && mv folio ~/.local/bin/
folio version

หรือใช้ Homebrew ซึ่งตรวจไฟล์ที่ดาวน์โหลดกับ checksum และติดตั้งให้คุณ:

brew install nawaman/tap/folio

จากนั้น folio init จะสร้าง store ของคุณ ในโฟลเดอร์ที่มีแค่คุณเข้าได้ (700) และ folio help แสดงคำสั่งที่เหลือ สำหรับ Tab completion ให้เพิ่ม eval "$(folio completion bash)" ลงใน ~/.bashrc หรือแบบ zsh ลงใน ~/.zshrc

สรุป

secret ของคุณไม่ควรอยู่ในไฟล์ .env, shell profile หรือ history เก็บมันไว้ใน store pass ที่เดียว เขียนไว้ครั้งเดียวว่าแต่ละโปรเจกต์ต้องการอะไร แล้วให้ folio exec ส่งค่าให้คำสั่งที่ต้องใช้ และไม่ส่งให้อะไรอื่นอีก เมื่องานย้ายไปเครื่องอื่น ไฟล์ export ที่เข้ารหัสก็ตามไปด้วย และไม่ทิ้งอะไรไว้เบื้องหลัง

เก็บ secret ของคุณให้พ้นสายตา

ลิงก์

Comments

Thank you for keeping the comment section positive, constructive and respectful. I appreciate constructive criticism & respectful disagreement!

0 / 5000