Oktaã®ã¢ããªã±ã¼ã·ã§ã³å²ãå½ã¦å¤±æãAmazon EventBridgeã§Slackã«éç¥ãã
Oktaã®ã¢ããªã±ã¼ã·ã§ã³ã®å²ãå½ã¦å¦çã失æããã¨ãã«Slackéç¥ãè¡ãæ°ä»ãããããã¾ããã Okta logãAmazon EventBridgeã«ã¹ããªã¼ãã³ã°ããEventBridgeããç´æ¥Slackã«ã¡ãã»ã¼ã¸ãéãã¾ãã
課é¡
Oktaã§ã¢ããªã±ã¼ã·ã§ã³ãã¢ãµã¤ã³ããå¾ãOktaããSaaSã«å¯¾ãã¦ã©ã¤ã»ã³ã¹å²ãå½ã¦ã®å¦çãè¡ããã¾ãããSaaSå´ã®åé¡ã§å¤±æãã¦ããæãããã¾ãã ã¢ãµã¤ã³ãã¦å³æã¨ã©ã¼ãåºãããã§ã¯ãªãã®ã§ããã«æ°ã¥ããªããã¨ãããã¾ãã ã¿ã¹ã¯ã«ã¯ä¸è¦§è¡¨ç¤ºããããã©å¸¸ã«è¦ã¦ããããããªãã
失æããçç±ã¨ãã¦ã¯ãSaaSå´ã§ã©ã¤ã»ã³ã¹ãä¸è¶³ãã¦ããå ´åã ã£ãããMicrosoftã®ä»æ§ã§Teamsã®è©¦ç¨çãã»ã«ãã§éå§ãã¦ããå ´åãªã©ãããã¾ãã
ç¶ããèªãWindows 365ã§Android Studioã®Android Emulatorã使ããããã«Intuneã§é å¸ãã
Windows 365ã®Cloud PCã®æ¤è¨¼ãé²ãã¦ãã¾ãããæ¥åã¨ãã¦ãã¢ããªã®æ¤è¨¼ã®ããAndroid Studioãã¤ã³ã¹ãã¼ã«ãã¦ãAndroid Emulatorãèµ·åãããã¨ãããã®ãããã¾ããã ããã£ãã®ã§ãã¾ã¨ãã¦ããã¾ãã
tl;dr
- Android Emulatorãèµ·åããããã«ã¯ãHyper-Vã®æå¹åãå¿ è¦
- Hyper-Vãæå¹ã«ããã«ã¯4 vCPU以ä¸ãå¿ è¦
æ®éã«ã¤ã³ã¹ãã¼ã«ãã¦åãã
Windows 365ã®Cloud PCä¸ã«Android Studioãã¤ã³ã¹ãã¼ã«ãã¦ãã¤ã¡ã¼ã¸ããã¦ã³ãã¼ããã¦ãã¾ããã ããã§â¶ï¸ãæ¼ãã°æ®éã¯èµ·åããã®ã§ããã

Install Android Emulator hypervisor driverã¨ã¨ã©ã¼ãåºã¦ãOKãæ¼ãã¨ã¤ã³ã¹ãã¼ã«ã«é²ã¿ã¾ãã


ãªãã ãã©ãStartService FAILED with error 4294967201ã¨ããã¨ã©ã¼ã§ãµã¼ãã¹ã®éå§ã«å¤±æããã

AEHDã¯ãGitHubããå¥éã¤ã³ã¹ãã¼ã«ã§ããã®ã§ãããã¤ã³ã¹ãã¼ã«ãã¦ããInstall Android Emulator hypervisor driverã®ã¨ã©ã¼ã¯åºã¦ããã®ãè¬
Hyper-Vãæå¹ã«ãã
StartService FAILED with error 4294967201ã®ã¨ã©ã¼ã§èª¿ã¹ã¦ã¿ãã¨ãHyper-Väºã ã®è©±ãåºã¦ããã®ã§ãæå¹ã«ãã¦ã¿ã¾ãã Windows 365ã¯ä»®æ³PCãªã®ã§ãnested virtualizationã¨ãããã¨ã«ãªãã¾ãã
ããã« 4vCPU 以ä¸ã®ã¯ã©ã¦ã ã¨æ¸ããã¦ããã®ã§ãCloud PCã®ã¹ããã¯ã4vCPUã«å¤æ´ãã¾ããã
ããã¦ã管çè æ¨©éã®Powershellã§ã³ãã³ããå®è¡ãã¾ãã
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
åèµ·åãã¦Hyper-Vãæå¹ã«ãªãã¾ãã
ããä¸åº¦è©¦ã
Hyper-Vãæå¹ã«ãªã£ãCloud PCã§Android Emulatorãèµ·åãã¾ãã ã ãã¶å¾ ãããããã©ç¡äºVirtual Deviceãèµ·åãã¾ããããã£ããã

ã¡ãªã¿ã«AEHDãåé¤ãã¦ãAEHDäºã ã®è¦åã¯åºããèµ·åãã¾ãã (Android Emulator hypervisor driver is a hypervisor to accelerate Android Emulator ã¨ãããã¨ã§ãããã©ã¼ãã³ã¹ã«å½±é¿ã¯ãããããããªã)
ã¨ãããã¨ã§ããããAppã¨ãã¦é å¸ããããã«æºåãã¾ãã
Hyper-Vã®æå¹åã¢ããª
å¿ è¦ãªäººã ãæå¹ã«ãããããã¢ããªã¨ãã¦é å¸ãã¾ãã
ãã¡ãã®è¨äºãåèã«ããã¦ãããã¾ããã
ãã¤ãã® Microsoft Win32 Content Prep Tool ã§intunewinãã¡ã¤ã«ã使ãã¾ãã 以ä¸ã®ãã¡ã¤ã«ãå«ãã¾ãã
enable.ps1
#Check if Hyper-V is enabled and enable it if necessary if((Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-Hypervisor).State -eq "Disabled") { Write-host "Enabling Microsoft Hyper-V...." Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All -NoRestart } else { Write-host "Microsoft Hyper-V was already succesfully installed" }
disable.ps1
Disable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -NoRestart
Intune管çã»ã³ã¿ã¼ã®ã¢ããªããWindowsã®ã¢ããªã Windowsã¢ã㪠(Win32) ã§ä½æã㦠intunewinãã¡ã¤ã«ãã¢ãããã¼ããã¾ãã

ããã°ã©ã ã®ç»é¢ã§ã¯ä»¥ä¸ãè¨å®ãã¾ãã
- ã¤ã³ã¹ãã¼ã« ã³ãã³ã:
Powershell.exe -NoProfile -ExecutionPolicy ByPass -File .\enable.ps1 - ã¢ã³ã¤ã³ã¹ãã¼ã«ã³ãã³ã:
Powershell.exe -NoProfile -ExecutionPolicy ByPass -File .\disable.ps1 - ããã¤ã¹ã®åèµ·å: Intuneã«ãã£ã¦ããã¤ã¹ã®å¿ é ã®åèµ·åãå¼·å¶å®è¡ãããããã«ãã

å¿ è¦æ¡ä»¶ã§ã¯ãå¿ è¦ãªè«çããã»ããµã®æå°æ°ã4ã«è¨å®ãã¾ãã

æ¤åºè¦åã§ã¯ãã«ã¹ã¿ã æ¤åºã¹ã¯ãªããã使ç¨ããããã«ãã以ä¸ã®ã¹ã¯ãªãããã¢ãããã¼ããã¾ãã
$exit_code = -1 if((Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-Hypervisor).State -eq "Enabled") { $exit_code = 0 } else { $exit_code = 1 } Write-Output "Exit Code: $exit_code" exit $exit_code

Android Studioã®é å¸
Android Studioã®exeãã¡ã¤ã«ãWin32 Content Prep Toolã§intunewinãã¡ã¤ã«ã«å¤æãã¦ãç²ã ã¨è¨å®ããæµãã§ããã
- ããã°ã©ã
- ã¤ã³ã¹ãã¼ã« ã³ãã³ã:
android-studio-2024.1.1.11-windows.exe /S - ã¢ã³ã¤ã³ã¹ãã¼ã« ã³ãã³ã:
"C:\Program Files\Android\Android Studio\uninstall.exe" /S
- ã¤ã³ã¹ãã¼ã« ã³ãã³ã:
- æ¤åºã«ã¼ã«
- æ¤åºè¦å:
ãã¡ã¤ã« C:\Program Files\Android\Android Studio\bin
- æ¤åºè¦å:
ã¨ãä¾åé¢ä¿ã¨ãã¦ãå ã«ä½æããHyper-Væå¹åã®ã¢ããªã®èªåã¤ã³ã¹ãã¼ã«ãè¨å®ãã¦ãã ããã
AWS SAM + Slack Bolt for Pythonã§Slack botãã¤ãã
æ¸ãããã¨
- Lazy Listenerãå©ç¨ããackãå¿ è¦ãªã¤ãã³ããã¤3ç§ä»¥ä¸æéããããå¦çãå®ç¾ãã
- Lambda Function URLãå©ç¨ãã¦HTTP Endpointãã¤ãã
Slack Bolt for Pythonã§Slack botãã¤ãã
ãã®ãã¥ã¼ããªã¢ã«ãåç §ãã¤ã¤ãã¤ããã¾ãã岿ã
ããç¨åº¦ããã¥ã¼ããªã¢ã«ã«æ²¿ã£ã¦ããã¼ã«ã«ã§Socket Modeæå¹ã§ã¤ãã£ã¦ãããLambdaã§åããããã«æ¬¡ã®Lazy Listernerãæå¹ã«ããããã«èªåã¯ãã¦ãã¾ãã
Lazy Listenerã®å©ç¨
Boltã§åããããã¤ãã³ãã¯å種ããã¾ãããã¢ã¯ã·ã§ã³ï¼actionï¼ãã³ãã³ãï¼commandï¼ãã·ã§ã¼ãã«ããï¼shortcutï¼ããªãã·ã§ã³ï¼optionsï¼ãããã³ã¢ã¼ãã«ããã®ãã¼ã¿éä¿¡ï¼view_submissionï¼ãå¦çããå ´åã¯ãSlackå´ããã®ãªã¯ã¨ã¹ãã«å¯¾ãã¦3ç§ä»¥å
ã« ack() ãè¿ãå¿
è¦ãããã¾ãã
ãã ãLambdaã§åããå ´åãHTTPã¬ã¹ãã³ã¹ãè¿å´ããã¿ã¤ãã³ã°ã§ããã»ã¹ãçµäºããããããackãè¿ãããã¨ã«å¦çãç¶ç¶ããããã¨ãã§ãã¾ããããã®å¯¾å¿ã¨ãã¦ãSlack Bolt for Pythonã§ã¯ãLazy Listenerã¨ããæ©è½ãæä¾ããã¦ãã¾ãã
ããã¯ãHTTPã§Slackãããªã¯ã¨ã¹ããåãåã£ãLambdaããã»ã¹ããæéã®ãããå¦çãå®è¡ããLambdaãéåæã§å¼ã³åºãã¦ãackã¬ã¹ãã³ã¹ãè¿å´ãããã¨ã§å®ç¾ããã¦ãã¾ãã
ä¾ã«ããããã«ãack ã¨ã lazy ã®å¼æ°ã«ããããackå¦çã¨ãæéã®ãããå¦çãåãã¦æ¸ãã¾ããlazyã«ã¯è¤æ°ã®é¢æ°ã渡ãããããã並åã«å®è¡ããã¾ãã
lazyã«1ã¤å¦çãæå®ããå ´åã1ã¤ã®ã¤ãã³ãã«å¯¾ãã¦ackå¦çã¨lazyå¦çã§Lambdaã2度invokeããããã¨ã«ãªãã¾ããä¸ã«æ¸ãã¦ããackãå¿
è¦ãªã¤ãã³ã以å¤ããã³ãã«ããå ´åã¯ackãä¸è¦ãªã®ã§ããã®å ´åLazy Listenerã使ãã¨ç¡é§ã«invokeã®åæ°ãå¢ããã®ã§ããã®å ´åã¯Lazy Listenerãæå¹ã«ããªãã»ããããã§ãã
以ä¸ã¯ãè¡é ã«Helloãããã¯helloã¨ããæååããã£ãã¨ãã«Hello!ãçºè¨ããå ´åã§ãã (messageã¤ãã³ãã¯ackãä¸è¦ãªã®ã§lazyã使ãå¿ è¦ã¯ãªãã§ã)
import logging import re from slack_bolt import App, Say from slack_bolt.adapter.aws_lambda import SlackRequestHandler SlackRequestHandler.clear_all_log_handlers() logging.basicConfig(level=logging.INFO) app = App(process_before_response=True) def handle_message(message, say: Say): print(message) say("Hello!") rule = re.compile("^[Hh]ello") app.message(rule)( ack=lambda ack: ack(), lazy=[handle_message] ) def handler(event, context): print("invoked", event) slack_handler = SlackRequestHandler(app=app) return slack_handler.handle(event, context)
ã¨ã«ããackã ãè¿ããããã°
ack=lambda ack: ack(),
ã¨æ¸ãã°OK
å¼ã³åºããCloudWatch Metricsã«putãã
Slack botãä½ã£ãå ´åãSlackããã®å¼ã³åºãã¯åãLambda Functionãå¼ã³åºãããã ããªã®ã§ãè¤æ°ã®ã¤ãã³ãããã³ããªã³ã°ããå ´åãã©ã®ã¤ãã³ããã©ã®ãããå¼ã³åºããã¦ããã®ãã調ã¹ãã®ãå°é£ã§ãããã®ã¨ãCloudWatch metricsã«ã¡ããªãã¯ãè¨é²ããã¨ä¾¿å©ã§ãã
以ä¸ã®ããã«å®ç¾©ãã¦ãhandle_shortcut ã§ã¯ackãã¤ã¤modalãéãããããdo_something ã§ã¯æéã®ãããå¦çãè¡ããstep_handle_shortcut ã§ã¯CloudWatch metricsã«ã¡ããªãã¯ãè¨é²ãã¾ãã
do_something 㨠step_handle_shortcut ã¯ä¸¦åã«invokeããã¾ãã
app.shortcut("shortcut")(
ack=handle_shortcut,
lazy=[do_something, metric.step_handle_shortcut]
)
metric.py ã§ã¯
import boto3 import os import datetime def put(step: str): client = boto3.client("cloudwatch") env = os.getenv("ENV") # å¥éå®ç¾©ãã response = client.put_metric_data( Namespace=f"FooBarSlackApp/{env}", MetricData=[ { "MetricName": "Request", "Dimensions": [ { "Name": "Step", "Value": step }, ], "Timestamp": datetime.datetime.utcnow(), "Value": 1, }, ] ) print(response) def step_handle_shortcut(): put("handle_shortcut")
SAMã§ãããã¤
æä½éå¿ è¦ãªã®ã¯ Lambda Function ã¨ãHTTP Endpointã¨ãã¦ã®Lambda Function URLã§ãã HTTP Endpointã¨ãã¦API Gateway (v1, v2) ãå©ç¨ãã¦ããä¾ããã£ãããã¾ãããç¹ã«é«åº¦ãªå®ç¾©ãå¿ è¦ãªããã°ãLambda Function URLã使ç¨ããã»ãããå®ç¾©ãç°¡åã§ããã¤ãå©ç¨æéãLambdaå´ã«å«ã¾ããã®ã§å®ä¾¡ã«ãªãã¾ãã(大æµã¯ã¾ã誤差ã¿ãããªéé¡ã ã¨æãã¾ãã)
src/ é
ä¸ã«ã³ã¼ããé
ç½®ããå ´åã以ä¸ã®ãããªã³ã¼ãã§å®ç¾ã§ãã¾ãã
AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: Slack bot sample Resources: HandlerFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: app.handler Runtime: python3.11 Timeout: 30 Policies: - AWSLambdaRole FunctionUrlConfig: AuthType: NONE Outputs: HandlerFunctionUrl: Value: !GetAtt HandlerFunctionUrl.FunctionUrl
FunctionUrlConfig ãå®ç¾©ãã¦ããã¨ãLambda Function URLãæå¹ã«ãªãã¾ããSlackããã®ãªã¯ã¨ã¹ãã«IAMèªè¨¼ãå©ç¨ãããã¨ã¯ã§ããªãã®ã§ãAuthType: NONE ã«ãªãã¾ãã(boltå
ã§Slackã®ç¹å®ã®ã¢ããªããæ¥ãæ£å½ãªãªã¯ã¨ã¹ãã signing_secret ãå©ç¨ãã¦æ¤è¨¼ãã¦ãã¾ã)
Slack appã® Interactivity eventsã®URLãSlash commandã®URLãEvent Subscriptionsã®URL (ããããæå¹ã«ãããã¯ä½¿ãã¤ãã³ã次第) ã«ãã®Lambda Function URLã®URLãæå®ãã¦ããå¿
è¦ãããã®ã§ãOutputs ã§åºåããã¦ãã¾ãã
SAMã§ãªã½ã¼ã¹ãåæã«ä½ããã¦ããã®ååã Lambda Functionåã« Url ãè¶³ãããã®ã«ãªãã®ã§ãLambda Functionã HandlerFunction ã®å ´åã HandlerFunctionUrl ã«ãªãã¾ãã
AWS CLIã§åå¨ããNode.js 10.xã®Lambda颿°ãä¸è¦§ãã
[è¦å¯¾å¿] AWS Lambda ã«ããã Node.js 10 ã®ãµãã¼ãçµäº | [Action Required] AWS Lambda end of support for Node.js 10 ã®ã¡ã¼ã«æ¥ã¦ããã©ãã©ãã«ãããã ã¨ããã£ãã
tl;dr
以ä¸ãå®è¡
REGIONS=`aws ec2 describe-regions --query 'Regions[*].RegionName' --output text` for region in $REGIONS; do aws lambda list-functions \ --function-version ALL \ --region $region \ --query "Functions[?Runtime=='nodejs10.x']" --no-cli-pager done
- regionä¸è¦§ã¨ã£ã¦åãã
--function-version ALLã§LATEST以å¤ã®ãã¼ã¸ã§ã³ãåå¾ãã- è¦ã¤ãã£ãããCloudWatch Metricã§Invocationããã¦ãããã確èªãã¦ã使ããã¦ãªãã£ããåé¤ããã
AWS Configã§ãªã½ã¼ã¹ã«ç´ä»ããªãã»ãã¥ãªãã£ã°ã«ã¼ããæ½åº
tl;dr
- 使ã£ã¦ããªãã»ãã¥ãªãã£ã°ã«ã¼ããåæããã
- ã»ãã¥ãªãã£ã°ã«ã¼ãã¯ENIã«å¯¾ãã¦å²ãå½ã¦ãENIãEC2ãªã©ã®ãªã½ã¼ã¹ã«ã¢ã¿ããããã¦ããã使ã£ã¦ããªãã»ãã¥ãªãã£ã°ã«ã¼ã = ã©ã®ENIã«ãå²ãå½ã¦ããã¦ããªãã»ãã¥ãªãã£ã°ã«ã¼ãããªã®ã ããåå¾ããã®ã¯ã»ãã¥ãªãã£ã°ã«ã¼ããåæããENIãåæãã¦ãã¨ãã使¥ãå¿ è¦ã§EC2 APIå©ãã¦å¦çããã®å°å³ã«é¢å
- AWS Configãæå¹ã«ãã¦ãããªããã¯ã¨ãªã§ããæãã«ã¨ãããããªã¼ã¸ã§ã³ãã¾ãããããAggregatorã使ã£ã¦ãããªããã«ãã¢ã«ã¦ã³ããä¸çº
ã³ã¼ã
import json import boto3 client = boto3.client('config') query = "SELECT resourceId, awsRegion, resourceName, " \ "configuration.description, configuration.ipPermissions, " \ "configuration.ipPermissionsEgress, relationships " \ "WHERE resourceType = 'AWS::EC2::SecurityGroup'" results = [] response = client.select_resource_config(Expression=query, Limit=100) results.extend(response['Results']) while True: if 'NextToken' in response: response = client.select_resource_config(Expression=query, NextToken=response['NextToken'], Limit=100) results.extend(response['Results']) else: break for result in results: result = json.loads(result) for relationship in result['relationships']: if relationship['resourceType'] == 'AWS::EC2::NetworkInterface': #eni_id = relationship['resourceId'] break else: # é¢é£ããENIãç¡ã = ãªã½ã¼ã¹ã«é¢é£ä»ãããã¦ããªãã»ãã¥ãªãã£ã°ã«ã¼ã print('\t'.join( [result['awsRegion'], result['resourceId'], result['resourceName'], result['configuration']['description']]))
ãã«ãã¢ã«ã¦ã³ãçã³ã¼ã
select_aggregate_resource_config() ã«å·®ãæ¿ããã ãã§ãAWS Config Aggregatorã«å¯¾ãã¦ã¯ã¨ãªãå®è¡ã§ãã¾ãã便å©ã
import json import boto3 client = boto3.client('config') query = "SELECT accountId, resourceId, awsRegion, resourceName, " \ "configuration.description, configuration.ipPermissions, " \ "configuration.ipPermissionsEgress, relationships " \ "WHERE resourceType = 'AWS::EC2::SecurityGroup'" results = [] response = client.select_aggregate_resource_config(Expression=query, Limit=100, ConfigurationAggregatorName='<aggregator name>') results.extend(response['Results']) while True: if 'NextToken' in response: response = client.select_aggregate_resource_config(Expression=query, NextToken=response['NextToken'], Limit=100, ConfigurationAggregatorName='<aggregator name>') results.extend(response['Results']) else: break for result in results: result = json.loads(result) for relationship in result['relationships']: if relationship['resourceType'] == 'AWS::EC2::NetworkInterface': #eni_id = relationship['resourceId'] break else: # é¢é£ããENIãç¡ã = ãªã½ã¼ã¹ã«é¢é£ä»ãããã¦ããªãã»ãã¥ãªãã£ã°ã«ã¼ã print('\t'.join( ['"' + result['accountId'] + '"', result['awsRegion'], result['resourceId'], result['resourceName'], result['configuration']['description']]))