dockerコンテナ上のアプリをAWS Lambda上で呼び出すには、awslambdaricというのが必要なようです。 dockerイメージは以下のようになります。
# Define custom function directory ARG FUNCTION_DIR="/function" FROM --platform=linux/amd64 python:3.10-slim-bullseye ENV TZ="Asia/Tokyo" # Include global arg in this stage of the build ARG FUNCTION_DIR # Install aws-lambda-cpp build dependencies RUN apt-get update -y && \ apt-get install -y \ g++ \ make \ cmake \ unzip \ libcurl4-openssl-dev \ oathtool # Copy function code RUN mkdir -p ${FUNCTION_DIR} WORKDIR ${FUNCTION_DIR} COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . # Install the function's dependencies RUN pip install \ --target ${FUNCTION_DIR} \ awslambdaric ENV PLAYWRIGHT_BROWSERS_PATH=0 RUN python -m playwright install --with-deps chromium ENTRYPOINT [ "python", "-m", "awslambdaric" ] CMD [ "app.lambda_handler" ]
なぜ、わざわざ、dockerイメージを使用しているかって? それは、oathtoolコマンドを使用してOTPを生成し、多要素認証を突破したかったからです。
#!/usr/bin/env python # -*- coding: utf-8 -*- import asyncio from playwright.async_api import async_playwright import subprocess URL = "" MAILADDRESS = "" PASSWORD = "" SECRET = "" async def main(): async with async_playwright() as p: try: browser = await p.chromium.launch( args=[ '--autoplay-policy=user-gesture-required', '--disable-background-networking', '--disable-background-timer-throttling', '--disable-backgrounding-occluded-windows', '--disable-breakpad', '--disable-client-side-phishing-detection', '--disable-component-update', '--disable-default-apps', '--disable-dev-shm-usage', '--disable-domain-reliability', '--disable-extensions', '--disable-features=AudioServiceOutOfProcess', '--disable-hang-monitor', '--disable-ipc-flooding-protection', '--disable-notifications', '--disable-offer-store-unmasked-wallet-cards', '--disable-popup-blocking', '--disable-print-preview', '--disable-prompt-on-repost', '--disable-renderer-backgrounding', '--disable-setuid-sandbox', '--disable-speech-api', '--disable-sync', '--disk-cache-size=33554432', '--hide-scrollbars', '--ignore-gpu-blacklist', '--metrics-recording-only', '--mute-audio', '--no-default-browser-check', '--no-first-run', '--no-pings', '--no-sandbox', '--no-zygote', '--password-store=basic', '--use-gl=swiftshader', '--use-mock-keychain', '--disable-gpu', '--single-process', '--headless=new' ], slow_mo=1000) context = await browser.new_context() page = await context.new_page() await page.goto(URL) async with page.expect_navigation(): # ログイン await page.type("input[name=loginfmt]", MAILADDRESS) await page.click("input[type=submit]") await page.type("input[name=username]", MAILADDRESS) await page.click("button[type=submit]") await page.type("input[name=password]", PASSWORD) await page.click("button[type=submit]") token = await generate_token(SECRET) await page.type("input[id=security-code]", token) await page.click("button[type=submit]") await page.wait_for_timeout(10000) # 以下は省略 finally: await browser.close() async def generate_token(secret: str) -> str: cmd = ['oathtool', '--totp', '--base32', secret] out = subprocess.run(cmd, stdout=subprocess.PIPE) fa_string = out.stdout.decode() # 取得する文字列の最後に改行があるため、6文字で切る処理 string_2fa = fa_string[:6] return string_2fa def lambda_handler(event, context): asyncio.run(main()) if __name__ == "__main__": pass
特殊な環境だったため、chromiumが、うまく動かなくて非常にはまりました。
chromiumは、複数プロセスを立ち上げるので、それがどうも相性がわるかったようです。
シングルプロセスで起動するオプションをchromium起動時に指定する必要があります。
また、--disable-gpu
も付与しないとクラッシュします。