Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีจัดการข้อมูลลับของแอปพลิเคชันใน EC2

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

ตัวอย่างเช่น เรามีเว็บแอปพลิเคชันสำหรับผู้ใช้ที่สร้างขึ้นโดยใช้ Rails เมื่อทำการบูทเสร็จแล้ว แต่ละอินสแตนซ์จะต้องมี Rails นั้นพร้อมและรอตอบสนองต่อคำขอที่ส่งต่อโดยตัวโหลดบาลานซ์ ในการทำให้สิ่งนี้เกิดขึ้น ฉันได้สร้างแบบกำหนดเองขึ้นมาก่อน AMI โดยการถ่ายภาพอินสแตนซ์ของอินสแตนซ์ที่จัดเตรียมผ่าน Ansible ด้วยแอป nginx ฯลฯ จากนั้นฉันกำหนดค่ากลุ่มการปรับขนาดอัตโนมัติด้วยข้อมูลผู้ใช้ที่เรียกใช้สคริปต์ที่คัดลอกสิ่งที่ capistrano ทำสำหรับการปรับใช้ - จะดึงรหัสล่าสุดจาก git รันบันเดิล และอื่นๆ on.ดังนั้นเมื่อมีแอปและการอ้างอิงทั้งหมดอยู่ในสถานที่ จะยังเหลืออะไรอีก

ความลับของแอปพลิเคชัน:ความหายนะของผู้ทำให้ใช้งานได้

ความลับของแอปพลิเคชันทำให้เกิดความท้าทาย:คุณต้องการป้องกันไม่ให้ถูกจัดเก็บในที่ที่สามารถเปิดเผยได้ (เช่น พูดใน git repo ของคุณ) แต่คุณต้องการให้แอปพร้อมใช้งานเมื่อทำงาน และเนื่องจากการปรับขนาดอัตโนมัติ คุณไม่สามารถวางใจให้มนุษย์เข้ามาแทนที่แอปของคุณเมื่อต้องการ

คำตอบเดียวสำหรับปัญหานี้คือ Vault โดย Hashicorp เป็นซอฟต์แวร์ที่ยอดเยี่ยมที่เขียนขึ้นโดยเฉพาะเพื่อแก้ปัญหานี้ในการเก็บความลับของคุณไว้เป็นความลับจนกว่าแอปของคุณจะต้องการ อย่างไรก็ตาม ข้อเสียคือคุณต้องจัดเตรียมและจัดการห้องนิรภัย ซึ่งเป็นบริการอื่นที่คุณต้องทำงานต่อไป

อีกทางเลือกหนึ่งคือการบันทึกข้อมูลลับในที่จัดเก็บข้อมูลที่ใช้ร่วมกัน (S3 ตามปกติ) และตรวจสอบให้แน่ใจว่ามีเพียงอินสแตนซ์ของคุณเท่านั้นที่สามารถเข้าถึงที่ฝากข้อมูลและ/หรือคีย์นั้นได้ ซึ่งสามารถทำได้โดยใช้บทบาท IAM ซึ่งสามารถมีนโยบายเพิ่มให้กับบทบาทเหล่านั้นซึ่งให้สิทธิ์การเข้าถึงทรัพยากร S3 ที่ถูกจำกัด นั่นยังคงทำให้คุณเปิดรับแสงที่ไม่ต้องการ แต่ถ้าคุณเก็บความลับทั้งหมดเหล่านั้นไว้ในข้อความธรรมดาบน S3 เป็นไปได้ที่จะทำให้ผู้อื่นเข้าถึงข้อมูลนั้นได้โดยไม่ได้ตั้งใจ หรือแม้แต่คนทั้งโลก

คงจะดีไม่น้อยถ้าคุณสามารถเข้ารหัสความลับของคุณก่อนที่จะบันทึก S3 แล้วโหลดและถอดรหัสมันในแอปเมื่อคุณต้องการหรือไม่

ส่วนผสมลับ:บริการจัดการคีย์ของ Amazon

Key Management Service (KMS) ของ Amazon มี API สำหรับการโต้ตอบกับคีย์การเข้ารหัส เมื่อรวมกับบทบาท IAM และโมดูลการเข้ารหัส Aws::S3::Encryption จะใช้รหัสเพียงไม่กี่บรรทัดในการโหลดความลับของคุณลงในแอปพลิเคชันของคุณโดยที่ยังคงเข้ารหัสไว้บน S3

ก่อนที่ฉันจะเริ่ม ฉันต้องขอบคุณ Don Mills ที่เขียนโพสต์ที่ยอดเยี่ยมโดยใช้ KMS plus S3 เพื่อเก็บความลับ ฉันเปลี่ยนแนวทางของเขาเล็กน้อยโดยขึ้นอยู่กับบทบาทของ IAM และติดตามคีย์ KMS แยกกันแทนที่จะจัดเก็บข้อมูลคีย์พร้อมกับความลับใน S3

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

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

การสร้าง Roux:ชิ้นส่วน KMS และ IAM ที่เท่าเทียมกัน

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

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1476277816000",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:HeadObject"
            ],
            "Resource": [
                "arn:aws:s3:::yourbucket/secrets.yml"
            ]
        }
    ]
}

ด้วยการกำหนดค่าคีย์และนโยบายที่แนบมากับบทบาทนี้ คุณสามารถโต้ตอบกับ KMS และ S3 ผ่านอินสแตนซ์ Aws::S3::Encryption::Client ได้ นี่คือตัวอย่างโค้ดบางส่วนที่ดึงไฟล์ความลับและโหลดเนื้อหาลงในตัวแปรสภาพแวดล้อม:

begin
  es3 = Aws::S3::Encryption::Client.new(kms_key_id: ENV['KMS_KEY_ID'])
  YAML.load(es3.get_object(bucket: "yourbucket", key: "secrets.yml").body.read).each do |k, v|
    ENV[k] ||= v # Don't override local ENV settings
  end
rescue ArgumentError
  # Raised when no KMS_KEY_ID was found in ENV, so there's nothing to do
rescue Aws::S3::Errors::NoSuchKey
  # No secrets file was found, so there's nothing to do
end

ขั้นแรก เราสร้างอินสแตนซ์อ็อบเจ็กต์ใหม่ด้วย ID ของคีย์ KMS ARNfor คีย์ (แสดงในคอนโซล IAM เมื่อคุณสร้างคีย์) ถูกเก็บไว้ในตัวแปรสภาพแวดล้อม KMS_KEY_ID เมื่อคุณส่งรหัสคีย์ไปยังคอนสตรัคเตอร์ที่นี่ มันจะจัดการการดึงคีย์ถอดรหัสชั่วคราวสำหรับคุณ คุณสามารถระบุอินสแตนซ์ Aws::S3::Client เป็นตัวเลือกที่นี่ หากคุณต้องการใช้ชุดข้อมูลรับรองแยกต่างหากเพื่อพูดคุยกับ S3 มากกว่าที่คุณใช้เพื่อพูดคุยกับ KMS หากคุณตั้งค่าบทบาท IAM ก่อนหน้านี้ คุณไม่จำเป็นต้องทำ เนื่องจาก Aws::S3::Encryption::Client จะสร้างอินสแตนซ์ Aws::S3::Client ใหม่ให้กับคุณด้วยข้อมูลประจำตัวที่ได้รับจากบทบาท IAM

เมื่อไคลเอ็นต์ S3 ที่เข้ารหัสพร้อมใช้งานแล้ว ให้ใช้ #get_object เพื่อดึงข้อมูลจาก S3 และถอดรหัสโดยใช้คีย์ที่ KMS ให้มา เมื่อคุณมีข้อมูลแล้ว คุณสามารถทำสิ่งที่ต้องการได้ ข้อมูลของเราคือ YAML ดังนั้นเราจึงโหลดและยัดคู่คีย์/ค่าลงใน ENV เพื่อใช้งานโค้ดของแอปพลิเคชัน

วางโค้ดนี้ลงในไฟล์ initializer ในแอปพลิเคชัน Rails ของคุณ เท่านี้คุณก็พร้อมแล้ว เมื่อคุณมีความลับของคุณถูกเก็บไว้ใน S3 นั่นคือ :) สมมติว่าคุณมีคอนโซล IRB บนอินสแตนซ์ที่ทำงานด้วยบทบาท IAM ที่ถูกต้อง คุณสามารถทำสิ่งนี้เพื่อเก็บความลับของคุณ:

# Encrypt the data from /path/to/secrets.yml and store it on S3
Aws::S3::Encryption::Client.new(kms_key_id: ENV['KMS_KEY_ID']).
  put_object(bucket: "yourbucket", key: "secrets.yml", body: File.read("/path/to/secrets.yml"))

เสิร์ฟทันที

ตอนนี้คุณมีความลับที่พร้อมใช้งานเสมอสำหรับอินสแตนซ์ใหม่ที่เพิ่มในกลุ่มการปรับขนาดอัตโนมัติของคุณในขณะที่ยังคงเข้ารหัสลับไว้ ชนะทุกคน! :)