SORACOM へデータを送信する仮想デバイスを SORACOM Arc+EC2+AWS CDK で構築してみた

SORACOM Arc と EC2、AWS CDK で仮想デバイスの作成も簡単に!
2021.07.07

はじめに

CX事業本部の佐藤智樹です。

本日はクラスメソッドの創立記念日(7/7)なので、途中まで実装していたネタを投稿しようかと思います。

今回は、SORACOM Arc という仮想SIMを使用して、EC2からSORACOMへ通信するための仕組みをAWS CDKで実装してみます。 今までSORACOM内部のサービスを試すにはSIMカードやSIMカード接続用の端末が必要で、導入までに若干時間や手間がありました。今回のEC2からSORACOMまでの通信が可能になれば、クラウドに慣れている人にとっては手軽にSORACOM側へ任意のデータが送れるようになります。同じようなことがしたかった方の参考になれば幸いです。

本当はLambdaでやりたかったのですが、間に合わなそうなのでLambdaの実装はまた別途公開します。

AWS CDKのコード

コードではVPC、サブネット、SG、EC2など最低限の設定を行います。ec2内部で設定しているkeyNameは使いまわすため事前にコンソールなどからキーペアを作成してください。

ec2-stack.ts

import * as cdk from "@aws-cdk/core";
import * as ec2 from "@aws-cdk/aws-ec2";
import * as iam from "@aws-cdk/aws-iam";

export class Ec2Stack extends cdk.Stack {

  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, "VPC", {
      cidr: "192.168.0.0/16",
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "public",
          subnetType: ec2.SubnetType.PUBLIC,
        },
      ],
    });

    const publicSecurityGroup = new ec2.SecurityGroup(this, "PublicSecurityGroup", {
      vpc: vpc,
      allowAllOutbound: true,
    });

    // SSM接続用ロール、今回は未使用
    const soracomArcRole = new iam.Role(this, `soracom-arc-role`, {
      roleName: `soracom-arc-role`,
      assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
    });

    soracomArcRole.addToPolicy(
      new iam.PolicyStatement({
        actions: ["s3:GetEncryptionConfiguration"],
        resources: ["*"],
      })
    );

    soracomArcRole.addToPolicy(
      new iam.PolicyStatement({
        actions: [
          "ssm:UpdateInstanceInformation",
          "ssmmessages:CreateControlChannel",
          "ssmmessages:CreateDataChannel",
          "ssmmessages:OpenControlChannel",
          "ssmmessages:OpenDataChannel",
        ],
        resources: ["*"],
      })
    );

    const ec2Instance = new ec2.Instance(this, "soracom-arc-nat-instance", {
      vpc,
      securityGroup: publicSecurityGroup,
      role: soracomArcRole,
      vpcSubnets: vpc.selectSubnets({ subnetType: ec2.SubnetType.PUBLIC }),
      instanceName: "soracom-arc-nat-instance",
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.NANO),
      machineImage: ec2.MachineImage.genericLinux({ "ap-northeast-1": "ami-076d8ebdd0e1ec091" }),
      keyName: "soracom-arc-nat-instance-key",
    });
    
    // ローカルからの接続用IPを通す 
    publicSecurityGroup.addIngressRule(ec2.Peer.ipv4("xx.xx.xx.xx/32"), ec2.Port.tcp(22));

    // IP確認用
    new cdk.CfnOutput(this, "soracom-arc-nat-instance-out-ip", {
      value: ec2Instance.instancePublicIp,
    });
  }
}

実行後EC2のIPが出力されるのでメモしてください。

 ✅  ec2

Outputs:
ec2.soracomarcnatinstanceoutip = xx.xxx.xxx.xxx

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/ec2/XXXXXXXXXXXXXXXXXXXXXXXXXXXX

EC2上で soratun の設定

デプロイ後、ローカル端末から接続して soratun を導入します。SORACOM側でのSAMの作成など詳細な内容は飛ばします。詳細が気になる場合は以下の公式資料をご確認ください。

soratun の設定と SORACOMへの接続

キーペアを使ってローカルからEC2に接続して、SORACOMと接続するトンネルデバイスの整備などを自動で行ってくれる soratun を設定します。

※ SSMから接続したい場合は、設定だけしてあるので今回作成したインスタンスを指定して接続してください。

% ssh -i soracom-arc-nat-instance-key.pem \
  ubuntu@ec2-xx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
~~~
$ wget https://github.com/soracom/soratun/releases/download/v1.0.0/soratun_1.0.0_linux_arm64.tar.gz
$ tar xvf soratun_1.0.0_linux_arm64.tar.gz
soratun_1.0.0_linux_arm64/LICENSE
soratun_1.0.0_linux_arm64/README.md
soratun_1.0.0_linux_arm64/conf/soratun.service.sample
soratun_1.0.0_linux_arm64/soratun
$ cd soratun_1.0.0_linux_arm64
$ sudo cp soratun /usr/local/bin

上記で soratun コマンドの設定は完了です。

次はSORACOM Arc の接続用ファイル(今回は arc.json 内部に記録)を設定し、soratun を起動後、pingで SORACOM に接続できるか確認します。

※ bootstrap authkey のオプションは空ファイルに対して何度も設定すると新しい仮想SIMがそのたび生成されるのでご注意ください。既存のファイルを指定する場合は問題ありません。

$ soratun --config ./conf/arc.json bootstrap authkey
Virtual subscriber SIM ID: 00XXXXXXXXXXXXXXXXXXX
Created/updated configuration file: /home/ubuntu/soratun_1.0.0_linux_arm64/conf/arc.json
$ sudo soratun --config ./conf/arc.json up &
~~~
$ ping pong.soracom.io
PING pong.soracom.io (100.XXX.XXX.XXX) 56(84) bytes of data.
64 bytes from 100.XXX.XXX.XXX (100.XXX.XXX.XXX): icmp_seq=1 ttl=64 time=2.81 ms
64 bytes from 100.XXX.XXX.XXX (100.XXX.XXX.XXX): icmp_seq=2 ttl=64 time=2.69 ms

無事 ping での接続が確認できました。

2021/7/9追記 初回のbootstrapコマンド実行時に生成している arc.json を使い回す(同じファイルでbootstrapする)ことで起動時に毎回仮想SIMを作らなくても済みます。soratunのコマンドも毎回同様のものをインストールしているので、継続的に使用する場合はscpコマンドなどでsoratun配下のディレクトリごとローカルや別のストレージに保存して、EC2構築時にコピーするとより便利です。

所感

ネットワーク周りやCDK周りで手間取ってとりあえずEC2で作りましたが、テストしたいときだけAWS CDKから作成して cron でも組んでおけばデバイスを疑似的に再現してデータ送れて便利かと思うのでデバイス手元にない場合はぜひ試してみてください。

SORACOMへのPublisherの実装を何度も変更したりテストしたい場合は、このNATインスタンスを経由してLambdaからアクセスした方が効率よく開発できそうです。料金はLambda分や場合によってはNAT Gatewayを使ったりと追加で料金がかかるのでそこは要検討かと思います。