it-swarm.dev

AWS Cloudfront (dengan WAF) + API Gateway: bagaimana cara mengakses melalui Cloudfront?

Saya ingin meletakkan WAF di depan API Gateway, dan dengan info (sedikit) Saya menemukan itu hanya mungkin dengan menempatkan distribusi Cloudfront secara manual dengan WAF diaktifkan, di depan APIG. Ini agak memalukan, terutama karena APIG sekarang mendukung domain khusus secara native, tetapi seharusnya berfungsi.

Sekarang untuk membuat solusinya aman daripada hanya tidak jelas, saya ingin menegakkan bahwa API hanya dapat diakses melalui distro Cloudfront. Apa pilihan terbaik untuk melakukan ini?

  • Saya berharap dapat menggunakan 'Origin Access Identities' yang mirip dengan S3, tetapi tidak melihat bagaimana melakukannya.
  • Jika saya bisa menetapkan Pengguna IAM (atau peran?) Ke distro Cloudfront, saya bisa menggunakan fitur APIG IAM, tetapi saya tidak melihat bagaimana ini bisa dilakukan.
  • Saya bisa memerlukan kunci API di APIG, dan meneruskannya sebagai Header Kustom Asal dari Cloudfront. Itu bisa berhasil, selama kita tidak ingin menggunakan kunci API untuk tujuan lain, jadi saya tidak sepenuhnya senang tentang itu.
  • Pengarang kustom dummy (!) Dapat digunakan, dengan ekspresi validasi Token benar-benar memeriksa rahasia yang diteruskan sebagai Header Kustom Asal dari Cloudfront. Harus bekerja, ini lebih fleksibel, tetapi agak kotor ... atau tidak?

Ada ide yang lebih baik? Atau mungkin "cara yang tepat" untuk melakukannya ada tetapi saya mengabaikannya?

12
Free Willaert

Saya dari API Gateway.

Sayangnya, solusi terbaik yang kami miliki sampai sekarang adalah, untuk menyuntikkan header kustom Origin di CloudFront dan memvalidasi itu dalam customizer (opsi 4 dalam pertanyaan Anda).

Kami sudah menyadari keterbatasan ini dan solusi yang tidak terlalu bagus. Kami mencari untuk memberikan integrasi WAF yang lebih baik di masa depan, tetapi kami tidak memiliki ETA.

5
Balaji

Cara "benar" adalah menggunakan pembuat kustom di API Gateway seperti yang disebutkan oleh orang lain.

Cara "murah" adalah peluru 3, kunci api. Anda mungkin hanya akan menyediakan waf -> cloudfront -> api gateway jika Anda mencoba untuk menangkis serangan DDoS. Jadi, jika seseorang menemukan url gerbang api Anda dan memutuskan untuk melakukan itu alih-alih cloudfront, seorang penulis kustom berarti Anda sekarang menerima beban serangan terhadap lambda. Api gateway dapat menangani lebih dari 10k permintaan per detik, batas lambda default adalah 100 per detik. Bahkan jika Anda mendapat Amazon untuk meningkatkan batas Anda, apakah Anda bersedia membayar 10 ribu lambda per detik untuk serangan berkelanjutan?

Perwakilan AWS akan memberi tahu Anda, "Kunci API untuk identifikasi, bukan untuk otentikasi. Kunci tidak digunakan untuk menandatangani permintaan, dan tidak boleh digunakan sebagai mekanisme keamanan" https://aws.Amazon.com/blogs/ aws/rencana penggunaan-baru-untuk-Amazon-api-gateway/

Tetapi jujur ​​jika Anda tidak akan melakukan sesuatu yang lebih baik di lambda Anda daripada memvalidasi beberapa string raksasa campur aduk mengapa tidak meninggalkan beban dan biaya untuk orang lain. (Panjang kunci Maks adalah 128 karakter)

Mungkin Anda bisa memiliki fungsi lambda terjadwal untuk mengeluarkan kunci api baru dan memperbarui header cloudfront setiap 6 jam?

Jika Anda ingin menggunakan kunci api untuk hal-hal lain maka hanya memiliki satu gerbang api Asal untuk otentikasi, dan gerbang Asal dan api lainnya untuk segala sesuatu yang lain. Dengan cara ini dalam serangan DDoS Anda dapat menangani permintaan 10rb per detik untuk api auth Anda, sementara semua pelanggan lain yang sudah login memiliki 10rb kolektif per detik untuk menggunakan api Anda. Cloudfront dan waf dapat menangani 100K per detik sehingga mereka tidak akan menahan Anda dalam skenario ini.

Satu hal lagi yang perlu diperhatikan jika Anda menggunakan lambda di belakang api gateway, Anda bisa menggunakan lambda @ Edge dan langsung saja melewati api gateway bersama-sama. (Ini tidak akan cocok dengan kebanyakan skenario karena lambda @ Edge sangat terbatas, tapi saya pikir saya akan membuangnya di sana.)

Tapi akhirnya WE PERLU INTEGRASI WAF DENGAN API GATEWAY !! :)

3
Neo

Anda dapat menggunakan nama domain khusus dan mengarahkan DNS ke distribusi dengan WAF. Permintaan langsung ke distribusi API Gateway asli tidak akan berfungsi saat itu.

0

Dimungkinkan untuk memaksa akses melalui CloudFront melalui menggunakan fungsi Lambda @ Edge untuk SigV4 menandatangani permintaan Origin dan kemudian mengaktifkan auth IAM pada API Gateway Anda. Strategi ini dapat digunakan bersama dengan Kunci API di distribusi CloudFront Anda ( panduan untuk CloudFront + Kunci API ).

Dengan asumsi bahwa Anda telah menyiapkan API Gateway sebagai Asal untuk distribusi CloudFront Anda, pertama-tama Anda harus membuat fungsi Lambda @ Edge ( panduan untuk setup Lambda @ Edge ) dan kemudian memastikan peran eksekusi memiliki akses ke API Gateway yang ingin Anda akses. Untuk mempermudah, Anda dapat menggunakan kebijakan IAM yang dikelola AmazonAPIGatewayInvokeFullAccess dalam peran eksekusi Lambda Anda yang memberikannya akses untuk memohon API Gateway apa pun dalam akun Anda.

Kemudian, jika Anda menggunakan aws4 sebagai klien penandatanganan Anda, seperti inilah kode Lambda @ Edge Anda:

const aws4 = require("aws4");

const signCloudFrontOriginRequest = (request) => {
  const searchString = request.querystring === "" ? "" : `?${request.querystring}`;

  // Utilize a dummy request because the structure of the CloudFront Origin request
  // is different than the signing client expects
  const dummyRequest = {
    Host: request.Origin.custom.domainName,
    method: request.method,
    path: `${request.Origin.custom.path}${request.uri}${searchString}`,
  };

  // Include the body in the signature if present
  if (Object.hasOwnProperty.call(request, 'body')) {
    const { data, encoding } = request.body;
    const buffer = Buffer.from(data, encoding);
    const decodedBody = buffer.toString('utf8');

    if (decodedBody !== '') {
      dummyRequest.body = decodedBody;
      dummyRequest.headers = { 'content-type': request.headers['content-type'][0].value };
    }
  }

  // Use the Lambda's execution role credentials
  const credentials = {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    sessionToken: process.env.AWS_SESSION_TOKEN
  };

  aws4.sign(dummyRequest, credentials); // Signs the dummyRequest object

  // Sign a clone of the CloudFront Origin request with appropriate headers from the signed dummyRequest
  const signedRequest = JSON.parse(JSON.stringify(request));
  signedRequest.headers.authorization = [ { key: "Authorization", value: dummyRequest.headers.Authorization } ];
  signedRequest.headers["x-amz-date"] = [ { key: "X-Amz-Date", value: dummyRequest.headers["X-Amz-Date"] } ];
  signedRequest.headers["x-amz-security-token"] = [ { key: "X-Amz-Security-Token", value: dummyRequest.headers["X-Amz-Security-Token"] } ];

  return signedRequest;
};

const handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const signedRequest = signCloudFrontOriginRequest(request);

  callback(null, signedRequest);
};

module.exports.handler = handler;

Perhatikan bahwa jika Anda menyertakan suatu badan dalam permintaan Anda, Anda harus mengonfigurasi fungsi Lambda @ Edge secara manual untuk memasukkan tubuh melalui konsol atau SDK atau menyiapkan sumber daya khusus CloudFormation untuk memanggil SDK sejak CloudFormation belum mendukung mengaktifkan ini secara asli

0
Reed Hermes