この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
SORACOMには、開発者向けにAPIが提供されています。
今回は、「このデバイス(IMEI)って、どのSIM(IMSI)を使ってるんだっけ?」をあとで調べる方法があるか、SORACOM APIを使って試してみました。
おすすめの方
- SORACOM APIを使いたい方
- SORACOM APIをLambdaで使いたい方
- SORACOM APIでIMEIからSIM(IMSI)を調べたい方
- AWS SAMでLambdaを作りたい方
- パラメータストアのSecureStringをLambdaで取得したい方
SORACOM APIを使う準備
- SAMユーザ作成
- 認証情報取得
- SAMユーザのアクセス権限付与
- System ManagerのパラメータストアにSORACOM SAMユーザの認証情報を格納
- 認証キーID
- 認証キーシークレット
上記については、次のブログを参考に行います。
なお、今回のアクセス権限は下記となります。
{
"statements": [
{
"api": [
"Subscriber:listSubscribers"
],
"effect": "allow"
}
]
}
Lambdaを作る
sam init
sam init \
--runtime python3.8 \
--name Lambda-Soracom-Api-Search-Imsi-Sample \
--app-template hello-world \
--package-type Zip
SAMテンプレート
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda-Soracom-Api-Search-Imsi-Sample
Parameters:
SoracomKeyId:
Type: AWS::SSM::Parameter::Value<String>
Default: /SORACOM/SAM/KeyId
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.8
Timeout: 10
Policies:
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
Environment:
Variables:
SORACOM_KEY_ID: !Ref SoracomKeyId
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
HelloWorldFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
Outputs:
HelloWorldApi:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
requirements.txt
requests
Lambdaコード
お試し実装のため、下記となっています。本番運用時には適宜検討し、実装してください。
- APIトークンの有効期限はデフォルト設定です。
- レートリミットの考慮をしていません。
SORACOM API リファレンスを見る限り、「IMEIを指定して、情報取得する」というAPIは無さそうです。 そのため、下記の手順で探しました。
- 所持しているSIM情報の一覧を取得する
- 「最新のセッション情報内のIMEI」と「探したいIMEI」が一致するSIM情報を探す
なお、IMEIはセッション情報内に存在するため、次の点に注意する必要があります。今回は未考慮です。
- 該当のSIMが1度もデータ送信してない可能性
- 該当のSIMと機材(IMEI)の組み合わせが古い可能性
- 該当のSIMと機材(IMEI)の組み合わせが複数ある可能性
また、SIMがたくさんある場合は、SIM情報取得時に条件マッチを活用すると良いですね。
- tag_name
- tag_value
- status_filter
- など
app.py
import os
import json
import boto3
import requests
from typing import Tuple, Optional
ssm = boto3.client('ssm')
SORACOM_ENDPOINT = 'https://api.soracom.io/v1'
IMEI = '3xxxxxxxxxxxxx0'
def lambda_handler(event, context):
soracom_key_id = os.environ['SORACOM_KEY_ID']
soracom_secret = get_soracom_secret()
api_key, token = get_token(soracom_key_id, soracom_secret)
subscribers = get_subscribers(api_key, token)
imsi = search_imsi_by_imei(subscribers, IMEI)
return {
'statusCode': 200,
'body': json.dumps({
'imei': IMEI,
'imsi': imsi,
}),
}
def get_soracom_secret() -> str:
res = ssm.get_parameter(
Name='/SORACOM/SAM/Secret',
WithDecryption=True
)
return res['Parameter']['Value']
def get_token(soracom_key_id, soracom_secret) -> Tuple[str, str]:
headers = {'Content-Type': 'application/json'}
data = {
'authKeyId': soracom_key_id,
'authKey': soracom_secret,
}
resp = requests.post(f'{SORACOM_ENDPOINT}/auth', headers=headers, data=json.dumps(data))
d = resp.json()
return d['apiKey'], d['token']
def get_subscribers(api_key: str, token: str) -> list:
headers = {
'Content-Type': 'application/json',
'X-Soracom-API-Key': api_key,
'X-Soracom-Token': token,
}
resp = requests.get(f'{SORACOM_ENDPOINT}/subscribers', headers=headers)
return resp.json()
def search_imsi_by_imei(subscribers: list, imei: str) -> Optional[str]:
for item in subscribers:
if 'sessionStatus' not in item:
continue
if item['sessionStatus']['imei'] == imei:
return item['imsi']
return None
デプロイ
sam build
sam package \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-deploy
sam deploy \
--template-file packaged.yaml \
--stack-name Lambda-Soracom-Api-Search-Imsi-Sample-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
APIエンドポイントを確認する
aws cloudformation describe-stacks \
--stack-name Lambda-Soracom-Api-Search-Imsi-Sample-Stack \
--query 'Stacks[].Outputs'
動作確認
API Gatewayのエンドポイントにアクセスすると、IMSIが返ってきました。
$ curl https://xxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
{"imei": "3xxxxxxxxxxxxx0", "imsi": "4xxxxxxxxxxxxx8"}