Skip to content

AWS Lambda Function URL-ek korlátozása CloudFronthoz

Az AWS Lambda Function URL egy nagyszerű dolog, amely zökkenőmentesen illeszkedik az AWS serverless víziójába. Az S3 statikus tárhelyével és a CloudFronttal kombinálva ideális platformot jelent a nagy teljesítményű webhelyek hosztolásához anélkül, hogy a bonyolult alárendelt infrastruktúra kezelésével járó gondokkal kellene foglalkozni.

Az alapok: S3 statikus weboldal hosting

Statikus webhely tárhelyet még soha nem volt ilyen egyszerű létrehozni. Az Amazon S3 statikus tárhelyszolgáltatással egyszerűen feltölthetjük statikus oldalainkat egy S3 tárolóba, és engedélyezhetjük a nyilvános hozzáférést (az S3 tárhelyet mindenképpen nevezzük el a domain nevének megfelelően). Az interneten rengeteg cikket találhatunk, amelyek elmagyarázzák, hogyan kell beállítani az S3 statikus tárhelyet, ezért itt nem fogok további részletekbe bocsátkozni.

De vannak korlátok: Az S3 nem támogatja a HTTPS-t, ami a weboldalak tárhelyének de facto minimum feltétele. A HTTPS használatához be kell állítani az Amazon CloudFrontot. Ez rengeteg extra funkcióval jár, mint például GeoIP-korlátozás, gyorsítótárazás és ingyenes SSL-tanúsítvány. Arról nem is beszélve, hogy végre letilthatjuk az S3 nyilvános hozzáférését (ami biztonsági kockázatot jelenthet), és korlátozott hozzáférést adhatunk csak a CloudFrontnak (egy S3 házirenddel).

Pro tipp: Adjuk hozzá a CloudFront ListBucket engedélyeket az S3 tároló házirendjéhez, különben az ügyfél nem fog HTTP státuszkódokat kapni, beleértve a 404-es kódot is, amikor nem létező tartalomhoz próbál hozzáférni:

Mishi
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::roadtoaws.com",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::111111111111:distribution/AAAAAAAAAAAAA"
                }
            }
        },
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::roadtoaws.com/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::111111111111:distribution/AAAAAAAAAAAAA"
                }
            }
        }
    ]
}

A CloudFront gyorsítótárazása miatt nem ideális fejlesztéshez. Vagy helyben kell tesztelni a kódot, vagy a HTTPS engedélyezése nélkül. Ez a fő oka annak, hogy továbbra is jó lenne, ha az S3-ban is megjelenne a HTTPS-támogatás. 🔮

Legyen dinamikus

A statikus weboldalak már a múlté. Valószínűleg előbb-utóbb valamilyen dinamikus tartalomra lesz szükségünk. Bár sok olyan szolgáltatás létezik, amely olyan funkciókat biztosít, mint az e-mail küldés, a megjegyzések, amelyeket beilleszthetünk a statikus kódunkba, hogy dinamikussá tegye azt, valószínűleg saját kódot kell írniunk bizonyos funkciókhoz. Itt jönnek jól a Lambda Function URL-ek. Egy egyszerű Lambda függvénnyel kódot hajthatunk végre vagy más AWS-erőforrásokat használhatunk, amelyeket egy egyszerű HTTP-kérelemmel hívhatunk meg a böngésződben. De hogyan korlátozhatjuk ezt egy adott IP-re, tartományra vagy a CloudFrontra? 🤔

Az AWS az IAM-en keresztül történő hitelesítést ajánlja, és bár ez valóban biztonságos módszer, a fejlesztést kihívássá teszi. Az első dolog, amit láthatsz, az a CORS, ahol az eredetet egy tartományra állíthatod be. Sajnos ez nálam nem úgy működött, ahogy szerettem volna. Ez nem korlátozza a Lambdádat abban, hogy bármilyen IP-ről meg lehessen hívni. Itt beállíthatsz egy X-Custom fejlécet is, de ez sem igazán korlátozza a külső hozzáférést.

Ezután kerestem megfelelő IAM-engedélyeket, amelyeket a Lambda-funkciókhoz csatolhatok. A rendelkezésre álló házirendek között találtam az InvokeFunctionUrl-t, ahol hozzáadhatunk egy IP-címet, hogy a meghívást egy adott IP-re korlátozza. Ez remekül hangzik! Létrehozunk egy házirendet, és csatoljuk azt a Lambda Role-hoz. Sajnos ez sem korlátozza a Lambda hozzáférését.

Mi volt tehát a megoldásom? 🙋🙋🙋

1. Korlátozás kódban

Az első kézenfekvő megoldás a forrás IP-jének ellenőrzése a Lambda függvénnyel. Íme egy Node.js nyelvű mintakód (hasonló kódot más nyelvekhez is találhatsz az interneten):

const ipAddress = event.identity.sourceIP;

if (ipAddress === '52.84.106.111') {
  const error = {
      statusCode: 403,
      body: JSON.stringify('Access denied'),
  };
  
  return error;
} else {
  const hello = {
      statusCode: 200,
      body: JSON.stringify('Hello World!'),
  };
  
  return hello;
}

Bár ez nyilvánvalóan működik, extra kódot adsz hozzá egy olyan Lambda-funkcióhoz, amelynek elsődleges szerepe valami más elvégzése. Arról nem is beszélve, hogy ez növeli a futási időt és a Lambda által használt erőforrásokat. A legfontosabb, hogy hogyan lehetsz biztos abban, hogy a sourceIP változóban kapott IP valóban az az IP, ahonnan az ügyfél érkezik.

A legnagyobb gondom ezzel a megoldással az volt, hogy nem csak egy adott IP-re akartam korlátozni a funkcióimat, hanem az egész CloudFront disztribúcióra, így biztos lehetek benne, hogy az egyik statikus oldalamról hívják meg. Ezzel a módszerrel nagy gondot jelentene az összes CloudFront szerver naprakész listájának karbantartása. 📝📝

2. reCAPTCHA

Igen, jól hallottad, Google reCAPTCHA. Ez elsőre furcsán hangozhat, de ez az a megoldás, amit én a munkám során megvalósítottam, és megoldást nyújt a fenti kihívásokra.

A reCAPTCHA kód beágyazása statikus weboldalakba jó ötlet. Valójában a Google azt javasolja, hogy a kódot minden oldalra építsük be – nem csak azokra, amelyeken szükség van rá, például az űrlapok érvényesítésére -, mert így az algoritmus hatékonyabban tudja felismerni a csalárd használatot. A lambda függvényen belül most már validálhatom, hogy a felhasználó valóban meghívta-e a statikus weboldalamról a lambda függvényem URL-címét. Íme a kód, amelyet a reCAPTCHA-kérés ellenőrzésére használok:

const gRecaptchaResponse = event.queryStringParameters["g-recaptcha-response"];
    
    var verificationUrl = "https://www.google.com/recaptcha/api/siteverify?secret=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&response=" + gRecaptchaResponse;
    const recaptchaResult = await getRequest(verificationUrl);
    
    if (false == recaptchaResult.success || 0.5 > recaptchaResult.score) {
      return error;
    }

Végezetül

Az S3 statikus weboldal hosting a legegyszerűbb módja a serverless utazás megkezdésének. Bár vannak akadályok, mindig találhatsz serverless megoldást. 🏆

Published inOktatóanyag
0 0 votes
Article Rating
Subscribe
Visszajelzés
guest

Ez az oldal az Akismet szolgáltatást használja a spam csökkentésére. Ismerje meg a hozzászólás adatainak feldolgozását .

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments