นักเทียบท่าและรหัสผ่านที่ปลอดภัย


162

ฉันเพิ่งทดลองใช้ Docker เมื่อไม่นานมานี้เกี่ยวกับการสร้างบริการบางอย่างเพื่อเล่นกับและสิ่งหนึ่งที่ทำให้ฉันจู้จี้ได้ใส่รหัสผ่านใน Dockerfile ฉันเป็นนักพัฒนาดังนั้นการจัดเก็บรหัสผ่านในแหล่งที่มารู้สึกเหมือนเป็นหมัดต่อหน้า นี่ควรเป็นปัญหาไหม? มีวิธีการจัดการรหัสผ่านที่ดีใน Dockerfiles หรือไม่?


7
มีปัญหาแบบเปิดสำหรับ Github ที่ขอแนวทางปฏิบัติที่ดีที่สุดเกี่ยวกับ Docker และความลับปัญหาอยู่ที่นี่: github.com/docker/docker/issues/13490
Luís Bianchin

คำตอบ:


92

แน่นอนมันเป็นเรื่องกังวล โดยทั่วไปแล้ว Dockerfiles จะถูกเช็คอินในที่เก็บและแชร์กับผู้อื่น อีกทางเลือกหนึ่งคือการให้ข้อมูลประจำตัวใด ๆ (ชื่อผู้ใช้, รหัสผ่าน, สัญญาณอะไรที่สำคัญ) เป็นตัวแปรสภาพแวดล้อมที่รันไทม์ นี้เป็นไปได้ผ่าน-eอาร์กิวเมนต์ (สำหรับ vars แต่ละ CLI) หรือ--env-fileอาร์กิวเมนต์ (สำหรับตัวแปรหลายในไฟล์) docker runเพื่อ อ่านสิ่งนี้เพื่อการใช้งานด้านสิ่งแวดล้อมด้วยนักแต่งเพลง

ใช้--env-fileเป็นมั่นเหมาะตัวเลือกที่ปลอดภัยตั้งแต่นี้ช่วยป้องกันความลับที่แสดงในหรือในบันทึกถ้าใครใช้psset -x

อย่างไรก็ตาม env vars ก็ไม่ได้ปลอดภัยเช่นกัน พวกเขาสามารถมองเห็นได้ผ่านdocker inspectและด้วยเหตุนี้พวกเขาจะสามารถใช้ได้กับผู้ใช้ที่สามารถเรียกใช้dockerคำสั่ง (แน่นอนว่าผู้ใช้ทุกคนที่มีสิทธิ์เข้าถึงdockerบนโฮสต์นั้นก็มีรูทด้วย)

รูปแบบที่แนะนำของฉันคือการใช้สคริปต์เสื้อคลุมเป็นหรือENTRYPOINT CMDสคริปต์ตัวตัดคำแรกสามารถนำเข้าข้อมูลลับจากตำแหน่งภายนอกไปยังคอนเทนเนอร์ในขณะดำเนินการจากนั้นเรียกใช้แอปพลิเคชันโดยระบุความลับ กลไกที่แน่นอนของสิ่งนี้แตกต่างกันไปตามสภาพแวดล้อมของเวลาทำงานของคุณ ใน AWS คุณสามารถใช้การรวมกันของบทบาท IAM, Key Management Serviceและ S3 เพื่อเก็บความลับที่เข้ารหัสไว้ในที่เก็บ S3 สิ่งที่ชอบHashiCorp Vaultหรือcredstashเป็นอีกทางเลือกหนึ่ง

AFAIK ไม่มีรูปแบบที่เหมาะสมที่สุดสำหรับการใช้ข้อมูลที่ละเอียดอ่อนเป็นส่วนหนึ่งของกระบวนการสร้าง อันที่จริงฉันมีคำถาม SOในหัวข้อนี้ คุณสามารถใช้นักเทียบท่าสควอชเพื่อลบเลเยอร์ออกจากรูปภาพ แต่ไม่มีฟังก์ชั่นพื้นฐานใน Docker สำหรับจุดประสงค์นี้

คุณอาจพบความคิดเห็น shykes ในการกำหนดค่าในภาชนะที่มีประโยชน์


ดังที่ระบุไว้ในความคิดเห็นอื่น ๆ จะมี 2 เลเยอร์ (หลังจากเพิ่มและหลัง RUN แรก) ที่มี.configไฟล์
Petr Gladkikh

1
ดูเหมือนว่าตัวแปร env เป็นวิธีที่ดีที่สุด ฉันได้ดูสิ่งนี้ในบริบทของการพัฒนา TDDing Dockerfile
gnoll110

5
ผมกังวลว่าถ้ารหัสผ่านของคุณเป็นตัวแปร env docker inspectจะปรากฏใน
บาง

การติดตั้งเริ่มต้นของนักเทียบท่า (บน linux) ต้องใช้สิทธิ์ sudoer docker inspectวิ่ง หากผู้โจมตีสามารถ sudo ได้แล้วการฉุดรหัสผ่านของคุณออกจากตัวตรวจจับนักเทียบท่าอาจจะค่อนข้างต่ำในรายการสิ่งที่คุณสามารถทำผิดพลาดได้ รายละเอียดนี้ดูเหมือนจะเป็นความเสี่ยงที่ยอมรับได้สำหรับฉัน
GrandOpener

7
@GrandOpener ใช้กับสถานการณ์ที่มีผู้โจมตีโดยใช้ระบบของคุณเท่านั้น ถ้าฉันผลักรูปนักเทียบท่าไปยังที่เก็บและมันถูกคนอื่นดึงฉันไม่สนใจว่าพวกเขามี sudo ในระบบของตัวเองหรือไม่ แต่ฉันก็สนใจว่าพวกเขาเห็นความลับใน env ที่ไม่ควรอยู่
vee_ess

74

Dockerfileทีมงานของเราหลีกเลี่ยงการใส่ข้อมูลประจำตัวในที่เก็บดังนั้นหมายความว่าพวกเขาจะไม่ได้รับอนุญาตใน แนวปฏิบัติที่ดีที่สุดของเราภายในแอปพลิเคชันคือการใช้เครดิตจากตัวแปรสภาพแวดล้อม

docker-composeเราแก้ปัญหาสำหรับนี้โดยใช้

ภายในdocker-compose.ymlคุณสามารถระบุไฟล์ที่มีตัวแปรสภาพแวดล้อมสำหรับคอนเทนเนอร์ได้:

 env_file:
- .env

ตรวจสอบให้แน่ใจว่าจะเพิ่ม.envไป.gitignoreแล้วตั้งข้อมูลประจำตัวที่อยู่ภายใน.envไฟล์เช่น:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

จัดเก็บ.envไฟล์ไว้ในเครื่องหรือในสถานที่ปลอดภัยที่คนอื่น ๆ ในทีมสามารถคว้าได้

โปรดดู: https://docs.docker.com/compose/environment-variables/#/the-env-file


15
คุณสามารถทำได้โดยไม่ต้องใช้ไฟล์. env หากต้องการ เพียงใช้คุณสมบัติสภาพแวดล้อมในไฟล์ docker-compose.yml ของคุณ "ตัวแปรสภาพแวดล้อมที่มีเพียงคีย์เท่านั้นที่ได้รับการแก้ไขเป็นค่าของพวกเขาในเครื่องเขียนกำลังทำงานซึ่งจะเป็นประโยชน์สำหรับค่าลับหรือค่าเฉพาะโฮสต์"
D. Visser

1
มอบคุกกี้ให้ชายคนนี้! :) อ๋อนี่เป็นวิธีปฏิบัติที่ดีจริงๆฉันแค่ต้องการเพิ่มdocs.docker.com/compose/env-file สิ่งนี้ควรทำงานโดยอัตโนมัติ แต่ในนักเทียบท่าเขียนเวอร์ชัน 2 ดูเหมือนคุณจะต้องประกาศตามที่อธิบายไว้ในคำตอบนี้
เทียบเท่า 8

5
การใช้ตัวแปรสภาพแวดล้อมนั้นไม่สนับสนุนโดยทีมงานนักเทียบท่าเองเนื่องจาก env var สามารถมองเห็นได้ผ่าน / proc / <pid> / environ และการตรวจสอบนักเทียบท่า มันทำให้งงงวยวิธีการรับข้อมูลประจำตัวของผู้โจมตีที่ได้รับการเข้าถึงรูท แน่นอนว่าข้อมูลประจำตัวของ CVS ไม่ควรถูกติดตาม ฉันเดาวิธีเดียวที่จะป้องกันไม่ให้ผู้ใช้รูทได้รับเครดิตคือการอ่านข้อมูลประจำตัวจากในเว็บแอป (หวังว่าจะไม่อัปเดตไฟล์ proc environ) จากไฟล์ที่เข้ารหัสกระบวนการถอดรหัสลับขอรหัสผ่านอย่างปลอดภัย ฉันคิดว่าฉันจะลองกับหลุมฝังศพ: github.com/dyne/Tomb
pawamoy

.gitignoreเพื่อให้.envไฟล์ที่มีข้อมูลที่สำคัญไม่ได้รับการเช็คอินที่ GitHub ฉันค่อนข้างมั่นใจว่ามันจะไม่ทำงานหากคุณเพิ่มเข้าไป.dockerignore
theUtherSide

สวัสดี @ theUtherSide ขอบคุณสำหรับคำตอบของคุณฉันมีคำถามเมื่อฉันไม่ตรวจสอบ.envไฟล์และฉันทำการปรับใช้กับเซิร์ฟเวอร์ในสถานที่ตั้งคุณแนะนำให้สร้าง.envไฟล์อีกครั้งบนเซิร์ฟเวอร์ด้วยตนเองหรือไม่
opensource-Developer

37

นักเทียบท่าตอนนี้ (เวอร์ชั่น 1.13 หรือ 17.06 ขึ้นไป) รองรับการจัดการข้อมูลลับ นี่คือภาพรวมและเอกสารรายละเอียดเพิ่มเติม

มีคุณสมบัติที่คล้ายกันในkubernetesและDCOS


บางคำสั่งที่มีประโยชน์จากลิงก์ด้านบนdocker secret create:: สร้างความลับ docker secret inspect: แสดงข้อมูลโดยละเอียดเกี่ยวกับความลับ docker secret ls: ดูความลับทั้งหมด docker secret rm: ลบความลับเฉพาะ --secretสำหรับdocker service create: สร้างความลับในระหว่างการสร้างบริการ --secret-addและการตั้ง--secret-rmค่าสถานะสำหรับdocker service update: อัปเดตค่าของความลับหรือลบความลับ ระหว่างงานอัพเดทบริการ ความลับของนักเทียบท่าได้รับการป้องกันที่เหลือในโหนดผู้จัดการและได้รับการจัดสรรให้กับโหนดผู้ปฏิบัติงานเมื่อในระหว่างการเริ่มต้นคอนเทนเนอร์
PJ

7
ใช่คุณต้องตั้งค่าฝูงเพื่อใช้ความลับของนักเทียบท่า
Heather QC

11
นี่เป็นการเริ่มต้นที่ดีสำหรับคำตอบ แต่ต้องการข้อมูลเพิ่มเติมจากสิ่งที่เชื่อมโยงเพื่อให้ปรากฏในคำตอบนั้นเอง
Jeff Lambert

7
ไม่แน่ใจว่านี่เป็นคำตอบที่ได้รับการยอมรับหากใช้ได้กับฝูงเท่านั้น หลายคนไม่ได้ใช้ฝูง แต่ยังต้องผ่านความลับ
John Y

9

คุณไม่ควรเพิ่มข้อมูลรับรองลงในคอนเทนเนอร์เว้นแต่ว่าคุณจะเผยแพร่เครดิตให้ใครก็ตามที่สามารถดาวน์โหลดภาพได้ โดยเฉพาะอย่างยิ่งการทำและADD credsหลังจากRUN rm credsนั้นไม่ปลอดภัยเนื่องจากไฟล์ creds ยังคงอยู่ในอิมเมจสุดท้ายในเลเยอร์ระบบไฟล์ระดับกลาง เป็นเรื่องง่ายสำหรับทุกคนที่สามารถเข้าถึงรูปภาพเพื่อแยก

วิธีการแก้ปัญหาทั่วไปที่ฉันเคยเห็นเมื่อคุณต้องการเครดิตเพื่อชำระเงินการอ้างอิงและเช่นการใช้ภาชนะหนึ่งเพื่อสร้างอีก นั่นคือโดยทั่วไปแล้วคุณจะมีสภาพแวดล้อมการสร้างในคอนเทนเนอร์พื้นฐานของคุณและคุณต้องเรียกใช้เพื่อสร้างแอปคอนเทนเนอร์ของคุณ ดังนั้นทางออกที่ง่ายคือการเพิ่มแหล่งที่มาของแอปของคุณแล้วRUNคำสั่งสร้าง สิ่งนี้ไม่ปลอดภัยหากคุณต้องการเครดิตในสิ่งRUNนั้น แทนสิ่งที่คุณทำคือใส่แหล่งที่มาของคุณลงในไดเรกทอรีท้องถิ่นให้เรียกใช้ (ในdocker run) ภาชนะเพื่อดำเนินการขั้นตอนการสร้างด้วยไดเรกทอรีแหล่งท้องถิ่นที่ติดตั้งเป็นปริมาณและเครดิตฉีดหรือติดตั้งเป็นปริมาณอื่น เมื่อขั้นตอนการสร้างเสร็จสมบูรณ์คุณจะสร้างที่เก็บข้อมูลสุดท้ายโดยเพียงแค่ADDไดเรกทอรีไดเรกทอรีท้องถิ่นซึ่งตอนนี้มีสิ่งประดิษฐ์ที่สร้างขึ้น

ฉันหวังว่านักเทียบท่าจะเพิ่มคุณสมบัติบางอย่างเพื่อทำให้สิ่งนี้ง่ายขึ้น!

อัปเดต: ดูเหมือนว่าวิธีการในอนาคตจะมีบิวด์ที่ซ้อนกัน กล่าวโดยย่อ dockerfile จะอธิบายถึงคอนเทนเนอร์แรกที่ใช้สร้างสภาพแวดล้อมรันไทม์และจากนั้นสร้างคอนเทนเนอร์ซ้อนที่สองที่สามารถรวบรวมชิ้นส่วนทั้งหมดลงในคอนเทนเนอร์สุดท้าย วิธีนี้สิ่งที่ build-time ไม่ได้อยู่ในคอนเทนเนอร์ที่สอง นี่เป็นแอป Java ที่คุณต้องการ JDK สำหรับสร้างแอป แต่เพียง JRE สำหรับการเรียกใช้ มีข้อเสนอจำนวนหนึ่งที่ถูกกล่าวถึงให้เริ่มจากhttps://github.com/docker/docker/issues/7115และทำตามลิงก์บางส่วนสำหรับข้อเสนออื่น


7

อีกทางเลือกหนึ่งในการใช้ตัวแปรสภาพแวดล้อมซึ่งอาจทำให้เกิดความยุ่งเหยิงหากคุณมีจำนวนมากคือใช้โวลุ่มเพื่อสร้างไดเรกทอรีบนโฮสต์ที่สามารถเข้าถึงได้ในคอนเทนเนอร์

หากคุณใส่ข้อมูลรับรองทั้งหมดของคุณเป็นไฟล์ในโฟลเดอร์นั้นคอนเทนเนอร์สามารถอ่านไฟล์และใช้งานได้ตามที่ต้องการ

ตัวอย่างเช่น:

$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...

In the Docker container:

# echo Password is `cat /cfg/password.txt`
Password is secret

หลายโปรแกรมสามารถอ่านข้อมูลประจำตัวของพวกเขาจากไฟล์แยกดังนั้นวิธีนี้คุณสามารถชี้โปรแกรมเป็นหนึ่งในไฟล์


5

โซลูชันแบบรันไทม์เท่านั้น

นักเทียบท่ายังให้การแก้ปัญหาโหมดที่ไม่จับกลุ่ม (ตั้งแต่ v1.11: ความลับโดยใช้การผูกติด )

ความลับถูกติดตั้งเป็นไฟล์ด้านล่าง/run/secrets/โดยนักแต่งเพลง วิธีนี้จะช่วยแก้ปัญหาในเวลาทำงาน (การเรียกใช้คอนเทนเนอร์) แต่ไม่ได้อยู่ที่ build-time (การสร้างอิมเมจ) เนื่องจาก/run/secrets/ไม่ได้เมานต์ที่ build-time นอกจากนี้พฤติกรรมนี้ขึ้นอยู่กับการใช้งานคอนเทนเนอร์ด้วยนักเทียบท่าประกอบ


ตัวอย่าง:

Dockerfile

FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity

นักเทียบท่า-compose.yml

version: '3.1'
services:
  app:
    build: .
    secrets:
      - password

secrets:
  password:
    file: password.txt

เพื่อสร้างรัน:

docker-compose up -d

อ่านเพิ่มเติม:


2

ด้วยDocker v1.9คุณสามารถใช้คำสั่ง ARGเพื่อดึงอาร์กิวเมนต์ที่ส่งผ่านโดยบรรทัดคำสั่งไปยังรูปภาพเมื่อสร้างแอคชั่น เพียงใช้--build-argธง ดังนั้นคุณสามารถหลีกเลี่ยงการเก็บรหัสผ่านที่ชัดเจน (หรือข้อมูลที่มีเหตุผลอื่น ๆ ) บน Dockerfile และส่งต่อได้ทันที

แหล่งที่มา: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg

ตัวอย่าง:

Dockerfile

FROM busybox
ARG user
RUN echo "user is $user"

สร้างคำสั่งภาพ

docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .

ในระหว่างการสร้างมันพิมพ์

$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
 ---> c51f86c28340
Step 2 : ARG user
 ---> Running in 43a4aa0e421d
 ---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
 ---> Running in 4360fb10d46a
**user is capuccino**
 ---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9

หวังว่ามันจะช่วย! บาย.


26
อ้างอิงจากเอกสาร ARG ของ Docker : "ไม่แนะนำให้ใช้ตัวแปร build-time สำหรับการส่งรหัสลับเช่นคีย์ github ข้อมูลประจำตัวผู้ใช้และอื่น ๆ "
Lie Ryan

3
เพียงแค่สงสัยว่าทำไม Docker จึงไม่แนะนำให้ใช้--build-arg var=secretสำหรับการส่งคีย์ส่วนตัว SSH ไปยังรูปภาพไม่มีเหตุผลในการบันทึก มีใครอธิบายได้บ้าง
Henk Wiersema

2
@HenkWiersema ข้อมูลกระบวนการบันทึกและประวัติคำสั่งไม่ปลอดภัย ข้อมูลกระบวนการสามารถใช้ได้ทั่วไปและรวมถึงพารามิเตอร์บรรทัดคำสั่งทั้งหมด บ่อยครั้งที่การโทรเหล่านี้สิ้นสุดลงในบันทึกซึ่งสามารถเผยแพร่ได้ ไม่ใช่เรื่องผิดปกติสำหรับผู้โจมตีที่จะตรวจสอบข้อมูลเกี่ยวกับกระบวนการทำงานและไฟล์บันทึกสาธารณะแบบอวนลากสำหรับความลับ แม้ว่าจะไม่ใช่ข้อมูลสาธารณะ แต่ก็สามารถเก็บไว้ในประวัติคำสั่งของคุณซึ่งจะช่วยให้ใครบางคนได้รับความลับผ่านบัญชีที่ไม่ได้เป็นผู้ดูแลระบบ
tu-Reinstate Monica-dor duh

2
วิธีที่แนะนำในการจัดหาข้อมูลประจำตัวที่จำเป็นในการสร้างเวลาคืออะไร? ตัวอย่างเช่นรูปภาพที่ต้องการการเข้าถึง aws s3 เพื่อดึงชุดข้อมูลขนาดใหญ่ที่จะอยู่ในภาพหรือไม่
ely

3
ฉันคิดว่าเหตุผลที่ไม่แนะนำคือเพราะdocker historyexposes build-arg/ ARGตัวแปร หนึ่งสามารถดึงภาพใด ๆ ตรวจสอบและดูความลับใด ๆ ที่ผ่านในระหว่างการสร้างเป็นพารามิเตอร์build-arg/ ARG
vee_ess

2

วิธีการของฉันดูเหมือนจะใช้ได้ แต่อาจไร้เดียงสา บอกฉันทีว่าทำไมมันผิด

ตั้งค่า ARG ในระหว่างการสร้างนักเทียบท่าถูกเปิดเผยโดยคำสั่งย่อยประวัติดังนั้นไม่ต้องไปที่นั่น อย่างไรก็ตามเมื่อเรียกใช้คอนเทนเนอร์ตัวแปรสภาพแวดล้อมที่กำหนดในคำสั่งเรียกใช้จะพร้อมใช้งานกับคอนเทนเนอร์ แต่ไม่ได้เป็นส่วนหนึ่งของอิมเมจ

ดังนั้นใน Dockerfile ทำการตั้งค่าที่ไม่เกี่ยวข้องกับข้อมูลลับ ตั้ง CMD /root/finish.shของสิ่งที่ต้องการ ในคำสั่ง run ให้ใช้ตัวแปรสภาวะแวดล้อมเพื่อส่งข้อมูลลับลงในคอนเทนเนอร์ finish.shใช้ตัวแปรเป็นหลักในการสร้างงานให้เสร็จ

เพื่อให้การจัดการข้อมูลลับง่ายขึ้นให้ใส่ลงในไฟล์ที่โหลดโดยนักเทียบท่าเรียกใช้ด้วย--env-fileสวิตช์ แน่นอนเก็บไฟล์เป็นความลับ .gitignoreและเช่น.

สำหรับฉันfinish.shรันโปรแกรม Python มันตรวจสอบเพื่อให้แน่ใจว่ามันไม่ได้ทำงานมาก่อนจากนั้นทำการตั้งค่าให้เสร็จสิ้น (เช่นคัดลอกชื่อฐานข้อมูลลงใน Django settings.py)


2

มีคำสั่งนักเทียบท่าใหม่สำหรับการจัดการ "ความลับ" แต่มันใช้ได้กับกระจุกดาวเท่านั้น

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 

1

วิธีแอป 12-Factorบอกว่าการกำหนดค่าใด ๆ ควรจะเก็บไว้ในตัวแปรสภาพแวดล้อม

นักเขียน Docker สามารถทำการทดแทนตัวแปรในการกำหนดค่าเพื่อให้สามารถใช้ในการส่งรหัสผ่านจากโฮสต์ไปยังนักเทียบท่า


ฉันขอขอบคุณอ้างอิงถึงพระคัมภีร์
JakeCowton

-2

ในขณะที่ฉันเห็นด้วยทั้งหมดไม่มีวิธีแก้ปัญหาง่าย ๆ ยังคงมีจุดล้มเหลวเพียงจุดเดียว มีทั้ง dockerfile, etcd และอื่น ๆ Apcera มีแผนที่ดูเหมือนเพื่อนสนิท - การรับรองความถูกต้องคู่ อีกนัยหนึ่งคอนเทนเนอร์สองตัวไม่สามารถพูดได้เว้นแต่จะมีกฎการกำหนดค่า Apcera ในการสาธิต uid / pwd นั้นชัดเจนและไม่สามารถนำกลับมาใช้ใหม่ได้จนกว่าผู้ดูแลระบบจะกำหนดค่าการเชื่อมโยง เพื่อให้ทำงานได้อย่างไรก็ตามอาจหมายถึงการแก้ไข Docker หรืออย่างน้อยก็ปลั๊กอินเครือข่าย (ถ้ามีสิ่งนั้น)


2
มีคำตอบในคำถามที่ถามหรือไม่
Abhijit Sarkar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.