API GatewayとECS Fargateで「rm -rf 」を実行するAPIを作ってみた

世界一無駄なAPIを作成してみました。
2022.03.23

世界一無駄なことをしたい

こんにちは、のんピ(@non____97)です。

以下記事で久しぶりにrm -rf /*をしたら意外と楽しかったので、また試してみたいと思います。

今回は、「API GatewayとECS Fargateで"rm -rf /*"を実行するAPI」を作ってみます。恐らく世界一無駄なAPIだと思います。

参考までにこのシリーズの過去の記事は以下の通りです。

ちょっとはチャレンジ要素がないとつまらないので、作成するリソースは全てAWS CDKで定義しました。コードは以下をご覧ください。

構成図

構成図は以下の通りです。

構成図

ALBもしくはNLBにアクセスするようにしても良かったのですが、無性にAPI Gatewayを触ってみたくなったので、API GatewayをNLBの前段に置いています。

コードの確認

まず、コードの確認をします。

今回はコンテナ上で動かすので、恐らくrm -rf /*したとしても、権限不足で盛大に怒られるのが目に見えています。

そこで、リクエストボディで指定した任意のディレクトリをrm -rfするといったものを作ります。

今回はコンテナ上で手っ取り早く動かしたかったので、Expressを使ってWebサーバーを立ち上げます。

また、rm -rf前後でどんなファイルが消されたか確認するために、rm -rf前後にls -lを実行します。

実際のコードは以下の通りです。

./src/images/rm-rf-root/src/index.ts

import * as express from "express";
import { spawnSync } from "child_process";

const app = express();

app.use(express.json());
app.use(
  express.urlencoded({
    extended: true,
  })
);

app.get("/", async (req: express.Request, res: express.Response) => {
  console.log("get /");
  res.status(200).json({ message: "rm -rf API" });
});

app.post("/", async (req: express.Request, res: express.Response) => {
  console.log("post /");

  console.log(req.body);
  const dir = req.body.dir;

  // Run "ls -l" before "rm -rf
  const cmd_before_ls_l_dir = spawnSync(`ls -l ${dir}`, { shell: true });
  console.log(`before ls -l ${dir} : ${cmd_before_ls_l_dir.stdout.toString()}`);

  // Run "rm -rf"
  const cmd_rm_rf_dir = spawnSync(`rm -rf ${dir}`, { shell: true });
  console.log(`rm -rf ${dir} stdout: ${cmd_rm_rf_dir.stdout.toString()}`);
  console.log(`rm -rf ${dir} stderr: ${cmd_rm_rf_dir.stderr.toString()}`);

  // Run "ls -l" after "rm -rf
  const cmd_after_ls_l_dir = spawnSync(`ls -l ${dir}`, { shell: true });
  console.log(`before ls -l ${dir} : ${cmd_after_ls_l_dir.stdout.toString()}`);

  res.status(200).json({
    cmd_before_ls_l_dir: `${cmd_before_ls_l_dir.stdout.toString()}`,
    cmd_after_ls_l_dir: `${cmd_after_ls_l_dir.stdout.toString()}`,
  });
});

app.listen(80, () => {
  console.log("Example app listening on port 80!");

  const cmd_pwd = spawnSync("pwd", { shell: true }).stdout.toString();
  const cmd_ls_l = spawnSync("ls -l", { shell: true }).stdout.toString();

  console.log(`
    pwd : ${cmd_pwd}
    ls -l : ${cmd_ls_l}
  `);
});

API GatewayやECS Fargateを作成はAWS CDKで行います。

コンテナイメージをビルドしてECRにプッシュする際はcdk-ecr-deploymentを使用しました。

API GatewayとNLBを連携させるにあたってはVPCリンクを使用します。VPCリンクの詳細な説明は以下記事をご覧ください。

実際のコードは以下の通りです。

./lib/api-stack.ts

import {
  Aws,
  Stack,
  StackProps,
  aws_ec2 as ec2,
  aws_ecr as ecr,
  aws_ecr_assets as ecr_assets,
  aws_ecs as ecs,
  aws_ecs_patterns as ecs_patterns,
  aws_apigateway as apigateway,
} from "aws-cdk-lib";
import { Construct } from "constructs";
import * as path from "path";
import * as ecr_deploy from "cdk-ecr-deployment";

export class ApiStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // VPC
    const vpc = new ec2.Vpc(this, "Vpc", {
      cidr: "10.0.0.0/24",
      enableDnsHostnames: true,
      enableDnsSupport: true,
      natGateways: 1,
      maxAzs: 2,
      subnetConfiguration: [
        { name: "Public", subnetType: ec2.SubnetType.PUBLIC, cidrMask: 27 },
        {
          name: "Private",
          subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
          cidrMask: 27,
        },
      ],
    });

    // ECR Repository
    const repository = new ecr.Repository(this, "Repository", {
      imageScanOnPush: true,
    });

    // Image
    const image = new ecr_assets.DockerImageAsset(this, "image", {
      directory: path.join(__dirname, "../src/images/rm-rf-root"),
    });

    // Deploy Image
    new ecr_deploy.ECRDeployment(this, "DeployImage", {
      src: new ecr_deploy.DockerImageName(image.imageUri),
      dest: new ecr_deploy.DockerImageName(
        `${Aws.ACCOUNT_ID}.dkr.ecr.${Aws.REGION}.amazonaws.com/${repository.repositoryName}`
      ),
    });

    // ECS Cluster
    const ecsCluster = new ecs.Cluster(this, "EcsCluster", {
      vpc,
      containerInsights: true,
    });

    // ECS Task Definition
    const taskDefinition = new ecs.FargateTaskDefinition(
      this,
      "TaskDefinition"
    );

    taskDefinition
      .addContainer("rm-rf-rootContainer", {
        image: ecs.ContainerImage.fromEcrRepository(repository, "latest"),
        memoryLimitMiB: 256,
        logging: ecs.LogDriver.awsLogs({
          streamPrefix: repository.repositoryName,
        }),
      })
      .addPortMappings({
        protocol: ecs.Protocol.TCP,
        containerPort: 80,
        hostPort: 80,
      });

    // NLB
    const loadBalancedFargateService =
      new ecs_patterns.NetworkLoadBalancedFargateService(
        this,
        "LoadBalancedFargateService",
        {
          assignPublicIp: false,
          cluster: ecsCluster,
          taskSubnets: vpc.selectSubnets({
            subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
          }),
          memoryLimitMiB: 1024,
          cpu: 512,
          desiredCount: 2,
          taskDefinition: taskDefinition,
          publicLoadBalancer: true,
        }
      );

    loadBalancedFargateService.service.connections.allowFrom(
      ec2.Peer.ipv4(vpc.vpcCidrBlock),
      ec2.Port.tcp(80)
    );

    // Auto Scaling Settings
    const scalableTarget =
      loadBalancedFargateService.service.autoScaleTaskCount({
        minCapacity: 2,
        maxCapacity: 10,
      });

    scalableTarget.scaleOnCpuUtilization("CpuScaling", {
      targetUtilizationPercent: 50,
    });

    scalableTarget.scaleOnMemoryUtilization("MemoryScaling", {
      targetUtilizationPercent: 50,
    });

    // VPC Link
    const link = new apigateway.VpcLink(this, "link", {
      targets: [loadBalancedFargateService.loadBalancer],
    });

    const getIntegration = new apigateway.Integration({
      type: apigateway.IntegrationType.HTTP_PROXY,
      integrationHttpMethod: "GET",
      options: {
        connectionType: apigateway.ConnectionType.VPC_LINK,
        vpcLink: link,
      },
    });
    const postIntegration = new apigateway.Integration({
      type: apigateway.IntegrationType.HTTP_PROXY,
      integrationHttpMethod: "POST",
      options: {
        connectionType: apigateway.ConnectionType.VPC_LINK,
        vpcLink: link,
      },
    });

    // API Gateway
    const api = new apigateway.RestApi(this, "Api");
    api.root.addMethod("GET", getIntegration);
    api.root.addMethod("POST", postIntegration);
  }
}

やってみた

npx cdk deployでAWS CDKで定義したリソースをデプロイします。

しばらくすると、ECSクラスターや、NLB、API Gatewayなどが作成されていることを確認できました。

ECSクラスター Amazon_ECS

NLB NLB

API Gateway API Gateway

また、CloudWatch Logsを確認すると、正しくWebサーバーが立ち上がっていることを確認できます。

> rm-rf-root@1.0.0 start /usr/src/app
> ts-node src/index.ts
Example app listening on port 80!
    pwd : /usr/src/app
    ls -l : total 48
-rw-r--r-- 1 root root   234 Mar 23 09:07 Dockerfile
drwxr-xr-x 1 root root  4096 Mar 23 09:08 node_modules
-rw-r--r-- 1 root root 22474 Mar 23 09:08 package-lock.json
-rw-r--r-- 1 root root   380 Mar 23 09:08 package.json
drwxr-xr-x 2 root root  4096 Mar 23 09:07 rm-test
drwxr-xr-x 2 root root  4096 Mar 23 09:07 src
-rw-r--r-- 1 root root   650 Mar 23 09:07 tsconfig.json

それでは、まずGETでリクエストをしてみます。

> curl https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/
{"message":"rm -rf API"}

俺は危険なAPIだぞ」というアピールをされました。

続いて、POSTでリクエストします。手始めにということで、リクエストボディには{"dir": "./Dockerfile"}を渡します。

> curl -H "Content-Type: application/json" -X POST https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/ -d '{"dir": "./Dockerfile"}'
{"cmd_before_ls_l_dir":"-rw-r--r-- 1 root root 234 Mar 23 07:23 ./Dockerfile\n","cmd_after_ls_l_dir":""}

"cmd_after_ls_l_dir":""となっていることからrm -rf./Dockerfileが削除されていることが確認できます。

CloudWatch Logsからも同様の結果を確認できました。

post /
{ dir: './Dockerfile' }
before ls -l ./Dockerfile : -rw-r--r-- 1 root root 234 Mar 23 07:23 ./Dockerfile
rm -rf ./Dockerfile stdout: 
rm -rf ./Dockerfile stderr: 
before ls -l ./Dockerfile :

もう一度リクエストボディを{"dir": "./Dockerfile"}にしてPOSTします。

> curl -H "Content-Type: application/json" -X POST https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/ -d '{"dir": "./Dockerfile"}'
{"cmd_before_ls_l_dir":"","cmd_after_ls_l_dir":""}⏎

既に./Dockerfileが削除されて存在しないので、cmd_before_ls_l_dir":""となっています。

次にリクエストボディを{"dir": "/"}としてPOSTします。

> curl -H "Content-Type: application/json" -X POST https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/ -d '{"dir": "/"}'
{"cmd_before_ls_l_dir":"total 72\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 bin\ndrwxr-xr-x  2 root root 4096 Jul 10  2020 boot\ndrwxr-xr-x  5 root root  340 Mar 23 07:26 dev\ndrwxr-xr-x  1 root root 4096 Mar 23 07:26 etc\ndrwxr-xr-x  1 root root 4096 Mar 17 13:01 home\ndrwxr-xr-x  1 root root 4096 Mar 16 00:00 lib\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 lib64\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 media\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 mnt\ndrwxr-xr-x  1 root root 4096 Mar 18 21:54 opt\ndr-xr-xr-x 96 root root    0 Mar 23 07:26 proc\ndrwx------  1 root root 4096 Mar 23 07:23 root\ndrwxr-xr-x  3 root root 4096 Mar 16 00:00 run\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 sbin\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 srv\ndr-xr-xr-x 13 root root    0 Mar 23 07:26 sys\ndrwxrwxrwt  1 root root 4096 Mar 23 07:23 tmp\ndrwxr-xr-x  1 root root 4096 Mar 16 00:00 usr\ndrwxr-xr-x  1 root root 4096 Mar 16 00:00 var\n","cmd_after_ls_l_dir":"total 72\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 bin\ndrwxr-xr-x  2 root root 4096 Jul 10  2020 boot\ndrwxr-xr-x  5 root root  340 Mar 23 07:26 dev\ndrwxr-xr-x  1 root root 4096 Mar 23 07:26 etc\ndrwxr-xr-x  1 root root 4096 Mar 17 13:01 home\ndrwxr-xr-x  1 root root 4096 Mar 16 00:00 lib\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 lib64\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 media\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 mnt\ndrwxr-xr-x  1 root root 4096 Mar 18 21:54 opt\ndr-xr-xr-x 97 root root    0 Mar 23 07:26 proc\ndrwx------  1 root root 4096 Mar 23 07:23 root\ndrwxr-xr-x  3 root root 4096 Mar 16 00:00 run\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 sbin\ndrwxr-xr-x  2 root root 4096 Mar 16 00:00 srv\ndr-xr-xr-x 13 root root    0 Mar 23 07:29 sys\ndrwxrwxrwt  1 root root 4096 Mar 23 07:23 tmp\ndrwxr-xr-x  1 root root 4096 Mar 16 00:00 usr\ndrwxr-xr-x  1 root root 4096 Mar 16 00:00 var\n"}

これでは訳がわからないのでCloudWatch Logsを確認します。rm -rf /をしようとしたけど--no-preserve-rootオプションがないため、怒られていますね。

post /
{ dir: '/' }
before ls -l / : total 72
drwxr-xr-x  2 root root 4096 Mar 16 00:00 bin
drwxr-xr-x  2 root root 4096 Jul 10  2020 boot
drwxr-xr-x  5 root root  340 Mar 23 07:26 dev
drwxr-xr-x  1 root root 4096 Mar 23 07:26 etc
drwxr-xr-x  1 root root 4096 Mar 17 13:01 home
drwxr-xr-x  1 root root 4096 Mar 16 00:00 lib
drwxr-xr-x  2 root root 4096 Mar 16 00:00 lib64
drwxr-xr-x  2 root root 4096 Mar 16 00:00 media
drwxr-xr-x  2 root root 4096 Mar 16 00:00 mnt
drwxr-xr-x  1 root root 4096 Mar 18 21:54 opt
dr-xr-xr-x 96 root root    0 Mar 23 07:26 proc
drwx------  1 root root 4096 Mar 23 07:23 root
drwxr-xr-x  3 root root 4096 Mar 16 00:00 run
drwxr-xr-x  2 root root 4096 Mar 16 00:00 sbin
drwxr-xr-x  2 root root 4096 Mar 16 00:00 srv
dr-xr-xr-x 13 root root    0 Mar 23 07:26 sys
drwxrwxrwt  1 root root 4096 Mar 23 07:23 tmp
drwxr-xr-x  1 root root 4096 Mar 16 00:00 usr
drwxr-xr-x  1 root root 4096 Mar 16 00:00 var
rm -rf / stdout: 
rm -rf / stderr: rm: it is dangerous to operate recursively on '/'
rm: use --no-preserve-root to override this failsafe
before ls -l / : total 72
drwxr-xr-x  2 root root 4096 Mar 16 00:00 bin
drwxr-xr-x  2 root root 4096 Jul 10  2020 boot
drwxr-xr-x  5 root root  340 Mar 23 07:26 dev
drwxr-xr-x  1 root root 4096 Mar 23 07:26 etc
drwxr-xr-x  1 root root 4096 Mar 17 13:01 home
drwxr-xr-x  1 root root 4096 Mar 16 00:00 lib
drwxr-xr-x  2 root root 4096 Mar 16 00:00 lib64
drwxr-xr-x  2 root root 4096 Mar 16 00:00 media
drwxr-xr-x  2 root root 4096 Mar 16 00:00 mnt
drwxr-xr-x  1 root root 4096 Mar 18 21:54 opt
dr-xr-xr-x 97 root root    0 Mar 23 07:26 proc
drwx------  1 root root 4096 Mar 23 07:23 root
drwxr-xr-x  3 root root 4096 Mar 16 00:00 run
drwxr-xr-x  2 root root 4096 Mar 16 00:00 sbin
drwxr-xr-x  2 root root 4096 Mar 16 00:00 srv
dr-xr-xr-x 13 root root    0 Mar 23 07:29 sys
drwxrwxrwt  1 root root 4096 Mar 23 07:23 tmp
drwxr-xr-x  1 root root 4096 Mar 16 00:00 usr
drwxr-xr-x  1 root root 4096 Mar 16 00:00 var

次にリクエストボディを{"dir": "/*"}としてPOSTします。

> curl -H "Content-Type: application/json" -X POST https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/ -d '{"dir": "/*"}'
{"message": "Endpoint request timed out"}

タイムアウトしてしまいましたね。

CloudWatch Logsを確認します。/sys/kernel/などを削除しようとして怒られていますね。当然です。

.
.
.
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/validate': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/free_calls': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/min_partial': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/poison': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/red_zone': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/slabs': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/destroy_by_rcu': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/sanity_checks': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/align': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/aliases': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/store_user': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/trace': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/reclaim_account': Read-only file system
rm: cannot remove '/sys/kernel/slab/:A-0000200/cgroup/vm_area_struct(800:postfix.service)/order': Read-only file system

最後に、リクエストボディを{"dir": "./*"}としてPOSTします。

> curl -H "Content-Type: application/json" -X POST https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/ -d '{"dir": "./*"}'
{"cmd_before_ls_l_dir":"-rw-r--r-- 1 root root   234 Mar 23 09:07 ./Dockerfile\n-rw-r--r-- 1 root root 22474 Mar 23 09:08 ./package-lock.json\n-rw-r--r-- 1 root root   380 Mar 23 09:08 ./package.json\n-rw-r--r-- 1 root root   650 Mar 23 09:07 ./tsconfig.json\n\n./node_modules:\ntotal 248\ndrwxr-xr-x  4 root root 4096 Mar 23 09:08 @cspotcode\ndrwxr-xr-x  6 root root 4096 Mar 23 09:08 @tsconfig\ndrwxr-xr-x 11 root root 4096 Mar 23 09:08 @types\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 accepts\ndrwxr-xr-x  4 root root 4096 Mar 23 09:08 acorn\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 acorn-walk\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 arg\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 array-flatten\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 body-parser\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 bytes\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 content-disposition\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 content-type\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 cookie\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 cookie-signature\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 create-require\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 debug\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 depd\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 destroy\ndrwxr-xr-x  4 root root 4096 Mar 23 09:08 diff\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 ee-first\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 encodeurl\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 escape-html\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 etag\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 express\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 finalhandler\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 forwarded\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 fresh\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 http-errors\ndrwxr-xr-x  4 root root 4096 Mar 23 09:08 iconv-lite\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 inherits\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 ipaddr.js\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 make-error\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 media-typer\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 merge-descriptors\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 methods\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 mime\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 mime-db\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 mime-types\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 ms\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 negotiator\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 on-finished\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 parseurl\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 path-to-regexp\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 proxy-addr\ndrwxr-xr-x  6 root root 4096 Mar 23 09:08 qs\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 range-parser\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 raw-body\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 safe-buffer\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 safer-buffer\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 send\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 serve-static\ndrwxr-xr-x  3 root root 4096 Mar 23 09:08 setprototypeof\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 statuses\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 toidentifier\ndrwxr-xr-x 11 root root 4096 Mar 23 09:08 ts-node\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 type-is\ndrwxr-xr-x  5 root root 4096 Mar 23 09:08 typescript\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 unpipe\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 utils-merge\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 v8-compile-cache-lib\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 vary\ndrwxr-xr-x  2 root root 4096 Mar 23 09:08 yn\n\n./rm-test:\ntotal 0\n-rw-r--r-- 1 root root 0 Mar 23 09:07 rm-file\n\n./src:\ntotal 4\n-rw-r--r-- 1 root root 1567 Mar 23 09:07 index.ts\n","cmd_after_ls_l_dir":""}

これも訳がわからないのでCloudWatch Logsを確認します。どうやらカレントディレクトリ配下を全て削除できているようです。

post /
{ dir: './*' }
before ls -l ./* : -rw-r--r-- 1 root root   234 Mar 23 09:07 ./Dockerfile
-rw-r--r-- 1 root root 22474 Mar 23 09:08 ./package-lock.json
-rw-r--r-- 1 root root   380 Mar 23 09:08 ./package.json
-rw-r--r-- 1 root root   650 Mar 23 09:07 ./tsconfig.json
./node_modules:
total 248
drwxr-xr-x  4 root root 4096 Mar 23 09:08 @cspotcode
drwxr-xr-x  6 root root 4096 Mar 23 09:08 @tsconfig
drwxr-xr-x 11 root root 4096 Mar 23 09:08 @types
drwxr-xr-x  2 root root 4096 Mar 23 09:08 accepts
drwxr-xr-x  4 root root 4096 Mar 23 09:08 acorn
drwxr-xr-x  3 root root 4096 Mar 23 09:08 acorn-walk
drwxr-xr-x  2 root root 4096 Mar 23 09:08 arg
drwxr-xr-x  2 root root 4096 Mar 23 09:08 array-flatten
drwxr-xr-x  3 root root 4096 Mar 23 09:08 body-parser
drwxr-xr-x  2 root root 4096 Mar 23 09:08 bytes
drwxr-xr-x  2 root root 4096 Mar 23 09:08 content-disposition
drwxr-xr-x  2 root root 4096 Mar 23 09:08 content-type
drwxr-xr-x  2 root root 4096 Mar 23 09:08 cookie
drwxr-xr-x  2 root root 4096 Mar 23 09:08 cookie-signature
drwxr-xr-x  2 root root 4096 Mar 23 09:08 create-require
drwxr-xr-x  3 root root 4096 Mar 23 09:08 debug
drwxr-xr-x  3 root root 4096 Mar 23 09:08 depd
drwxr-xr-x  2 root root 4096 Mar 23 09:08 destroy
drwxr-xr-x  4 root root 4096 Mar 23 09:08 diff
drwxr-xr-x  2 root root 4096 Mar 23 09:08 ee-first
drwxr-xr-x  2 root root 4096 Mar 23 09:08 encodeurl
drwxr-xr-x  2 root root 4096 Mar 23 09:08 escape-html
drwxr-xr-x  2 root root 4096 Mar 23 09:08 etag
drwxr-xr-x  3 root root 4096 Mar 23 09:08 express
drwxr-xr-x  2 root root 4096 Mar 23 09:08 finalhandler
drwxr-xr-x  2 root root 4096 Mar 23 09:08 forwarded
drwxr-xr-x  2 root root 4096 Mar 23 09:08 fresh
drwxr-xr-x  2 root root 4096 Mar 23 09:08 http-errors
drwxr-xr-x  4 root root 4096 Mar 23 09:08 iconv-lite
drwxr-xr-x  2 root root 4096 Mar 23 09:08 inherits
drwxr-xr-x  3 root root 4096 Mar 23 09:08 ipaddr.js
drwxr-xr-x  3 root root 4096 Mar 23 09:08 make-error
drwxr-xr-x  2 root root 4096 Mar 23 09:08 media-typer
drwxr-xr-x  2 root root 4096 Mar 23 09:08 merge-descriptors
drwxr-xr-x  2 root root 4096 Mar 23 09:08 methods
drwxr-xr-x  3 root root 4096 Mar 23 09:08 mime
drwxr-xr-x  2 root root 4096 Mar 23 09:08 mime-db
drwxr-xr-x  2 root root 4096 Mar 23 09:08 mime-types
drwxr-xr-x  2 root root 4096 Mar 23 09:08 ms
drwxr-xr-x  3 root root 4096 Mar 23 09:08 negotiator
drwxr-xr-x  2 root root 4096 Mar 23 09:08 on-finished
drwxr-xr-x  2 root root 4096 Mar 23 09:08 parseurl
drwxr-xr-x  2 root root 4096 Mar 23 09:08 path-to-regexp
drwxr-xr-x  2 root root 4096 Mar 23 09:08 proxy-addr
drwxr-xr-x  6 root root 4096 Mar 23 09:08 qs
drwxr-xr-x  2 root root 4096 Mar 23 09:08 range-parser
drwxr-xr-x  2 root root 4096 Mar 23 09:08 raw-body
drwxr-xr-x  2 root root 4096 Mar 23 09:08 safe-buffer
drwxr-xr-x  2 root root 4096 Mar 23 09:08 safer-buffer
drwxr-xr-x  3 root root 4096 Mar 23 09:08 send
drwxr-xr-x  2 root root 4096 Mar 23 09:08 serve-static
drwxr-xr-x  3 root root 4096 Mar 23 09:08 setprototypeof
drwxr-xr-x  2 root root 4096 Mar 23 09:08 statuses
drwxr-xr-x  2 root root 4096 Mar 23 09:08 toidentifier
drwxr-xr-x 11 root root 4096 Mar 23 09:08 ts-node
drwxr-xr-x  2 root root 4096 Mar 23 09:08 type-is
drwxr-xr-x  5 root root 4096 Mar 23 09:08 typescript
drwxr-xr-x  2 root root 4096 Mar 23 09:08 unpipe
drwxr-xr-x  2 root root 4096 Mar 23 09:08 utils-merge
drwxr-xr-x  2 root root 4096 Mar 23 09:08 v8-compile-cache-lib
drwxr-xr-x  2 root root 4096 Mar 23 09:08 vary
drwxr-xr-x  2 root root 4096 Mar 23 09:08 yn
./rm-test:
total 0
-rw-r--r-- 1 root root 0 Mar 23 09:07 rm-file
./src:
total 4
-rw-r--r-- 1 root root 1567 Mar 23 09:07 index.ts
rm -rf ./* stdout: 
rm -rf ./* stderr: 
before ls -l ./* :

もう一度リクエストボディを{"dir": "./*"}としてPOSTします。

> curl -H "Content-Type: application/json" -X POST https://nlhss0riw5.execute-api.us-east-1.amazonaws.com/prod/ -d '{"dir": "./*"}'
{"cmd_before_ls_l_dir":"","cmd_after_ls_l_dir":""}

カレントディレクトリは空のはずなのに元気にレスポンスを返してくれました。恐らくメモリ上に残った力で対応してくれているのでしょう。健気ですね。

CLP やってみるを体現した

API GatewayとECS Fargateで"rm -rf /*"を実行するAPIを作ってみました。

久しぶりにECSやAPI Gatewayを使ってみて今回も非常に有意義な時間を過ごせました。

この記事は誰の役にも立たないかもしれませんが、誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!