mattintosh note

田舎エンジニア物語 〜In Search of the Lost My Private Key〜

第六回博麗神社秋季例大祭とコミックマーケット97に申し込みました

タイトルの通りです。令和になって何を血迷ったか同人イベントにサークルとして申し込みました(画力無いのに)。これまで同人イベントには度々行っていたんですが、一般参加じゃなくてサークルとして参加してみたいなと思ったわけです(画力無いのに)。

仕事柄どうしても技術書系の内容くらいしか書けず、それをどう東方Projectと結びつけようかと悩んだ挙句、macOS ユーザ向けの東方ゲーム解説本のようなナニカになります。キャラは自分の一番好きな魔理沙を描こうと思っています。「○畜ちゃん」っぽい感じになる…かも。

同人イベントに申し込む時って「本の概要」を書いて送らなくてはいけないんですが、かなり支離滅裂な内容で出したと思います。今頃きっと運営様の方で「何かヤバイの来た」と思われてるかもしれません。

それ以外にも不安が多々あります。

例大祭で技術系の本を出しているサークルはあるの?場違いじゃないの?

多分無いと…思います。夏の例大祭で一応すべての配置を周って「その他」も見てきたのですが技術書的なものを頒布されているサークルは無かったような気がします。この時点で場違いではないかという不安しかない。

そして「ただ自分の書いた本に東方のキャラをいいように使ってるだけじゃない?」みたいな感じになってしまいそうなのがすごく怖い。(そうならないようにちゃんと漫画は描きたい…画力ないけど)

Windows ゲームを macOS で動かそうとする"悪魔の書"みたいなもの出して大丈夫?

Wine を使って macOS でも東方ゲームをやってる人って結構いるだろうし、やりたいと思っている人もいると思ってます。そんな人たちの役に立てれば…と考えたのですがこれもやっぱり不安。そもそも Wine で動かそうとする行為が自己責任であり、そのような行為を拡散させるような書物を総本山の目の前で頒布していいのだろうか…。

動作する保証が無いため EasyWine などの頒布ページにも「製作者様への問い合わせ等はご遠慮ください」と記載はしていますが、これもやっぱり不安。

EasyWine とかの説明書が欲しいと思っている方には申し訳ないですが EasyWine 普及用の同人誌ではないので EasyWine や Nihonshu のことについては掲載しません。

そんな語彙力で大丈夫?

あっ…(察し


という感じで今になって「何故申し込んだし」と思っているのですが、原稿の方はなんとか進めています。しかし、ここでも問題が。

現在の私はフル Linux 環境で生きている人間なので IllustratorInDesign なんてものは当然使えず、本を作る環境を作るのに苦労しています。PDF なら何とでもなるんですが、印刷所に入稿するデータを作るとなるとフォントサイズやレイアウト、ページデザイン、断ち切りのサイズ等を考慮しなくてはなりません。Linux はこの辺が圧倒的に不利だと感じています。

Inkscape は複数ページを扱えないので Scribus を2日ほど使ってみましたがこれで書籍を作るのは正直かなりシンドいといった印象です。ベジェ使いにくいしリドゥ効かない部分あるしでマジで心が折れそう。

結局、書き慣れた AsciiDoc で原稿を書いてあとから漫画のページや表紙等を Scribus で合成する方針に変更。それも無理ならあとは GhostScript なり ImageMagick を駆使するしかない…。漫画はアナログで書いたものをスキャナで取り込んで Krita でベタとか入れる予定。

形式(コピ本 or オフセ本、カラー or モノクロ etc)や価格もまだまだ未定です。何より運営様の趣旨に沿わないことや抽選で外れる可能性もあるのでサークルとして出られるかどうかはわかりません。

不安しかない(;´Д`)

ESP-WROOM-02 で IoT 夏休み自由研究

「イベント出るから IoT っぽいこと何かやってよ」と言われたので「何か」をやることにした。

LoRa でやろうかとも思ったけど制限多いし市内にゲートウェイあんま無いから使い物にならんなってことで Wi-Fi にした。

Wi-Fi 温度計(Wi-Fi Temperature Measurement)

ESP-WROOM-02 と汎用温度センサー LM61CIZ を使った Wi-Fi 温度計。ESP-WROOM-02 の TOUT は 1 V までしか扱えないので分圧等の対応が必要だが LM61CIZ は 0 ℃が 600 mV で 1 ℃ ごとに 10 mV 増えるので 1 V になるのは 40 ℃。つまり「会場が 40 ℃ を超えなければ問題ない!」ということで手抜きで Vo をそのまま TOUT に突っ込んである。データは MQTT で飛ばして Node-RED で表示。外付けの ADC を使えばいいのだけどこの程度の装置に付けるのはちょっとね。

f:id:mattintosh4:20190729183913p:plain
ESP-WROOM-02 Wi-Fi 温度計

アンテナ部分に貼ってあるテプラはチップ ID。複数の ESP-WROOM-02 があるとどれがどのデバイスかわからなくなるので ESP.getChipId() でチップ ID を取得して MQTT のトピックとして使っている。

Wi-Fi 土壌湿度計(Wi-Fi Moisture Measurement)

市販の土壌湿度計もあるけど割高なので自作。回路は土壌の抵抗値をトランジスタで変換するだけなので単純。これも TOUT の上限 1 V までになるように分圧で調整。土壌の抵抗値は土質によるが数百オームから数メガオームくらいまで変化するので抵抗の分圧だけで測定しようと思うと難しい(湿っているか乾いているかくらいざっくりしたものならトランジスタも使わなくていいと思う)。

f:id:mattintosh4:20190729184103p:plain
ESP-WROOM-02 土壌湿度計

試作品なので縦付け抵抗とワニ口クリップを使う。0 Ω 抵抗は見た目を合わせるだけに使ってる。

f:id:mattintosh4:20190729184222p:plain
ESP-WROOM-02 土壌湿度計

金メッキプラグで試してみたことがあるが腐食してしまうので今回は 2 mm の鉛筆芯を使うことにした。手持ちには 2H もあるのだけど B の方が抵抗値が少なかったので B を採用。芯自体の抵抗値は 7 Ω くらいだった気がする。

f:id:mattintosh4:20190729184300p:plain
ESP-WROOM-02 土壌湿度計

土がなかったのでメラミンスポンジで実験。

この投稿をInstagramで見る

水分量チェッカー(スポンジ試験

mattintosh4さん(@mattintosh4)がシェアした投稿 -

金メッキプラグを使用していたときはヘデラを育てていたのだけどプラグが腐食し始めてからプラグに近い部分の茎から徐々に枯れていったので植物に悪影響を及ぼしていそう。錫は錆にくいみたいだけど錫メッキされたものなら植物に影響を与えずに電極棒として使えるのかなぁ…。

IoT コンセント

手元にソリッドステートリレーが転がっていたので作ってみた。これと水槽用エアポンプ、ペットボトル、ソフトチューブを組み合わせて自動水やりができるようにした。自動水やりと言うとよく汲み上げ式のポンプを使っているのを見るのだけど、エアポンプでタンク内の圧力を高めて押し出す方が多分楽だと思う(霧吹きの原理)。

f:id:mattintosh4:20190729185725p:plain
ESP-WROOM-02 IoT コンセント

中継には PVK ボックスを使った。が、屋外用の大きめのボックスを使った方が 3.3 V の AC アダプターも中に入れておけたのでは…と後悔。コンセントを二系統にしたので SSR が二つになってかなり窮屈になった。

f:id:mattintosh4:20190729184558p:plain
ESP-WROOM-02 IoT コンセント

Node-RED のダッシュボードを FireTV のウェブブラウザから弄って水を出してみる。

この投稿をInstagramで見る

遠隔水やり装置作りました

mattintosh4さん(@mattintosh4)がシェアした投稿 -


という感じでぼくのなつやすみのじゆうけんきゅうはこれで終わり(にしたい)。

ESP-WROOM-02 のプルアップ抵抗ってだいたい 10 kΩ を使っている例が多いと思うけど 10 kΩ だとたまに起動しないことがある。今回は一番面倒な PVK ボックス内の ESP-WROOM-02 が突然起動しなくなったので EN のプルアップ抵抗を 1 kΩに変えたら動くようになった。今後は 4.7 kΩ くらいを使おうかな。

ネットで ESP8266 や ESP-WROOM-02 の使い方を見ているとよく IO0IO2 をプルアップしている例が見つかるが、ESP-WROOM-02 のデータシートを見てみると IO0IO2 もフローティングでいいっぽい(UART Download モードの場合は IO0 をプルダウンする必要はある)。

f:id:mattintosh4:20190730233140p:plain
ESP-WROOM-02 Datasheet

https://www.espressif.com/sites/default/files/documentation/0c-esp-wroom-02_datasheet_en.pdf

考えてみればスイッチサイエンスのピッチ変換基板シンプル版だと IO0IO2 をプルアップもしくはプルダウンしてしまうと何も接続できない。

www.switch-science.com

余計な配線も減らせるしもっと早くデータシート見ておけばよかった。

macOS の Wine で使えるゲームパッドを調べてみた

Wine でゲームパッドゲームコントローラー)使ったことがなかったので東方 Project 作品をプレイするにあたっていくつか購入したり借りたりして試しましたのでまとめておきます。

当然ですが macOS 対応を謳っている製品は少ないです。「PlayStation 用」とか「Windows 用」とだけ書いてあるものが macOS で使えたりもします。しかし、Mac もモデルや世代などで結構な種類がありますのですべての機種で同じように使えるかどうかはわかりません。その点をご理解いただいた上でお読みください。

有線(Wired)

Buffalo BSGP810GY

使用可です。個人的にアナログスティックが苦手なので十字キーがメインの方が好きです。東方をプレイするならこれくらいのボタン数の方がいいですね。

ODSeven ODS197 クラシックUSBゲームパッド for RaspberryPi/Windows/Mac

秋葉原千石電商さんで ¥500 で売っているスーパーファミコンゲームパッド。全体的に安っぽく、ベコベコします。十字キーがめちゃめちゃ使いにくいので東方をやるにはあまり向いていません。

www.sengoku.co.jp

ホリパッド3 ミニ

使用可です。アナログスティックも動作します。

【PS3対応】ホリパッド3 ミニ クリアブラック

【PS3対応】ホリパッド3 ミニ クリアブラック

無線(Wireless)

8BITDO Android/iOS/PC対応 Bluetooth&USB接続 ゲームコントローラ FC30 GAMECONTROLLER

Bluetooth 対応のファミコン風コントローラー。高いだけあって作りは最高です。秋葉原のあきばお〜さんに行けば多分いつでも買えます(店舗によっては取り扱ってないみたいです)。薄くて小さいので持ち運びも楽なんですが大人の手だとLRボタンを押すのがキツイです。

www.akibaoo.co.jp

SONY DUALSHOCK3

皆さんよくご存知のコントローラーですね。私は PlayStation というかゲーム機自体を所持していないので借りたものですが、macOS でも問題なくペアリング出来ました。ただ、ボタン配置が正規の配置になっているかどうかはわかりません。

HORI ワイヤレスコントローラーライト for PlayStation (R) 4 クリアブラック

使用不可です。初回のペアリングは出来るのですが、すぐに切断され、それ以降も接続出来ないため使用できません。Windows というか Windows 筐体?の Linux では普通に充電も出来ますしゲームパッドとしても使用可能です。小さくて持ち運びもしやすいので Linux ノート PC と一緒に持ち出すことがあります。Bluetooth 2台接続もできそうですが1台しか持っていないのでまだ試していません。他、以下のような特殊な謎仕様があるので別記事にでもしようかと思います。

  • 「有線では使えません」と説明書に書いてあるが(Linux では)有線でも使える(謎)
  • 有線と無線で繋いだときのボタン数の認識の仕方が違う(謎)
  • 一般的な USB 充電器で充電できない(謎)

まとめ

PlayStation を持っている人ならとりあえずプレステのコントローラーでいいんじゃないでしょうか。ボタン配置がめちゃくちゃなのでゲーム側で設定は必須ですが特に問題ないと思います。

自分は最初に HORI のワイヤレスコントローラーを買ったんですが、Mac では使えなかったので Linux 機用に。しかし、Mac でもワイヤレスで使えるゲームパッドがどうしても欲しくて 8BITDO のゲームパッドを買う羽目に。高いですが品質はめちゃくちゃいいですし、macOS 対応をしっかり謳っているのでよい買い物をしたと思うことにしています。

まぁ東方をやるときは一番使いやすい iBuffalo のスーパーファミコンゲームパッドを使っているのだが…。

孤独の AWS Cloud9 ハンズオン 〜Cloud9 は SSH 踏み台として使えるのか〜

先日、Amazon 本社で AWS スタートアップの説明を聞く機会があった。そこで「最近では踏み台に Cloud9 を使っている方も」という話を聞いたので「本当に踏み台として使えるのか」「Terraform との相性はどうなのか」というのを確認してみた。なお、Cloud9 には新規に EC2 インスタンスを作成するタイプと既存の EC2 インスタンスなどに Cloud9 IDE をインストールして Cloud9 environment として使う SSH タイプもあるが後者については触れない。

AWS Cloud9 とは

AWS Cloud9 はブラウザで使えるクラウド上の IDE。本来は開発目的で利用するものなんだろうが EC2 インスタンスを使っているので普通に踏み台として EC2 を構築するのとあまり変わらない。実際、既存の EC2 インスタンスに Cloud9 IDE をインストールしてそのまま「environment」として使うこともできる。

一般的な SSH 接続を中継する方法以外に Cloud9 IDE のターミナルからプライベートネットワークにあるインスタンスSSH 接続をするという選択肢がある。AWS マネジメントコンソールにアクセスでき、対象の「environment」でターミナルを使う権限があるユーザであれば SSH クライアントなしでプライベートネットワークに配置されているインスタンスにアクセスができる。ブラウザ上でファイル転送もできるので大抵のことは Cloud9 IDE 上でできるだろう。

他にも Cloud9 を使うメリットとしては以下のようなことが考えられる。

  • membership というもので IDE にアクセスできる(=ターミナルを利用できる)ユーザを管理することができる。
  • (Cloud9 IDE からしかアクセス出来ないと思われる)セキュリティグループを自動的に作成してくれる。名前は aws-cloud9-環境名-乱数 のような書式。
  • インアクティブな状態が続いた場合の自動シャットダウンを「30 分」「1 時間」「4 時間」「1 日」「1 週間」「なし」から設定することができる。踏み台用のインスタンスのコストを抑えることができる。

「お、これは結構使えるのでは?」と思ったが、試しているうちにデメリットも色々と出てきた。詳しくは後述するが、だいたい以下のような点。

  • Cloud9 用のインスタンスを作成したらサーバに接続するための秘密鍵を保存しておく必要がある。
  • 一般的な SSH 接続を中継する踏み台として利用する場合、セキュリティグループの編集が必要になったり、EIP を設定したりする必要がああるが自動化が難しい。

現時点での個人的な感想は「踏み台として『使える』か『使えない』かなら『使える』が、何か中途半端」といった感じ。

では孤独のハンズオンで色々と試していく。

Cloud9 environment の作成

Cloud9 では environment(以下、「Cloud9 environment」とする)と membership でアクセス制限を行っている。作成した Cloud9 environment の membership に IAM ユーザやロールを read-only または read-write のいずれかの権限で追加することによって複数のユーザで Cloud9 environment を共有することができるようになっている。

AWS マネジメントコンソールの Cloud9 メニューでは以下のように environment の種類が分かれている。

Your environment Owner が自身の ARN で登録されている Cloud9 environment が表示される。AWS マネジメントコンソールから作成した場合は必ずこちらに登録される。
Shared with you 対象の Cloud9 environment の membership に自身の ARN が read-only または read-write 権限で登録されている Cloud9 environment が表示される。
Account Environments AWS アカウントに登録されている Cloud9 environment が表示される。自身が Owner の Cloud9 environment 以外に、Owner でもなく membership でも登録されていない Cloud9 environment も表示される。Terraform や AWS CLI で Owner の ARN を指定しなかった場合はここにのみ表示される。

membership には read-onlyread-write 以外に owner があり、これは Cloud9 environment 作成時に自動的に作成される membership であり変更はできない。

AWS マネジメントコンソール、Terraform、AWS CLI で Cloud9 environment 作成時の挙動が異なるので以下にまとめておく。

AWS マネジメントコンソールから Cloud9 environment を作成する

「Name」は必須だが「Description」は任意。既に同名の Cloud9 environment が存在する場合は作成できない。(Owner が異なる場合は作成可能)

f:id:mattintosh4:20190714230009p:plain
AWS Cloud9

インスタンスタイプや配置する VPC、サブネットなどを選択する。インスタンスタイプは「Other instance type」を選択すれば好きなものを選ぶことができる。執筆時点ではここの「Amazon Linux」は「Amazon Linux 2」ではない。VPC やサブネットはデフォルトでは「デフォルト VPC」と「デフォルトサブネット」を使うようになっている。実際にはプロジェクト用に作成した VPC とサブネットに配置すると思うが、ここで気をつけなければならないのは Cloud9 environment を配置するサブネットはパブリックサブネットでなければならない。Cloud9 によって自動的に作成されるセキュリティグループを見ればわかるがインバウンドルールに Cloud9 用に予約されたネットワークからの 22 番接続を許可する設定が追加される。Cloud9 environment への接続へはグローバルから行われることになるため NAT ゲートウェイの有無に関わらずプライベートサブネットへ配置すると Cloud9 IDE にアクセスできなくなる。

f:id:mattintosh4:20190714230357p:plain
AWS Cloud9 - Create environment

設定内容を確認して[Create environment]ボタンをクリックする。

f:id:mattintosh4:20190714231315p:plain
AWS Cloud9 - Create environment

Cloud9 用のインスタンス作成が行われて接続画面に移行する。Cloud9 用の AMI から作成されているのでだいたい 60 秒もあれば使えるようになる。

f:id:mattintosh4:20190714231458p:plain
AWS Cloud9 - Cloud9 IDE

インスタンスの状態を確認してみる

f:id:mattintosh4:20190715011314p:plain

Cloud9 で作成される EC2 インスタンスとセキュリティグループは CloudFormation によって作成されているのでまずは CloudFormation のスタックを確認する。スタック名は aws-cloud9-{Cloud9環境名}-{Cloud9環境ID} となっている。Cloud9 environment の ID は Cloud9 IDE の URL か AWS CLIcloud9 list-environments で調べることができる。

aws cloudformation describe-stacks \
    --stack-name aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "StackName": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "CreationTime": "2019-07-14T14:59:45.535Z",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Tags": [
                {
                    "Key": "aws:cloud9:environment",
                    "Value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                },
                {
                    "Key": "aws:cloud9:owner",
                    "Value": "XXXXXXXXXXXXXXXXXXXXX:john"
                }
            ],
            "EnableTerminationProtection": false
        }
    ]
}

スタックのリソースを確認する。

Terminal

aws cloudformation describe-stack-resources --stack-name aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

ここから EC2 インスタンスの ID とセキュリティグループの ID がわかる。

Result

{
    "StackResources": [
        {
            "StackName": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "LogicalResourceId": "Instance",
            "PhysicalResourceId": "i-xxxxxxxxxxxxxxxxx",
            "ResourceType": "AWS::EC2::Instance",
            "Timestamp": "2019-07-14T15:00:31.775Z",
            "ResourceStatus": "CREATE_COMPLETE"
        },
        {
            "StackName": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "LogicalResourceId": "InstanceSecurityGroup",
            "PhysicalResourceId": "sg-xxxxxxxxxxxxxxxxx",
            "ResourceType": "AWS::EC2::SecurityGroup",
            "Timestamp": "2019-07-14T14:59:55.347Z",
            "ResourceStatus": "CREATE_COMPLETE"
        }
    ]
}

セキュリティグループは aws-cloud9-{Cloud9環境名}-{Cloud9環境ID}-InstanceSecurityGroup-{乱数} という名前で作成されているので、GroupName かタグ値で CloudFormation のスタック名をフィルタリングすればすぐ出てくるだろう。

Terminal

aws ec2 describe-security-groups --filters 'Name=group-name,Values=aws-cloud9-foo-*'

セキュリティグループのインバウンドルールには Cloud9 で予約されていると思われるネットワークアドレスが二つ登録されている。

Result

{
    "SecurityGroups": [
        {
            "Description": "Security group for AWS Cloud9 environment aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "GroupName": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-InstanceSecurityGroup-XXXXXXXXXXXXX",
            "IpPermissions": [
                {
                    "FromPort": 22,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "18.179.48.96/27"
                        },
                        {
                            "CidrIp": "18.179.48.128/27"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "ToPort": 22,
                    "UserIdGroupPairs": []
                }
            ],
            "OwnerId": "000000000000",
            "GroupId": "sg-xxxxxxxxxxxxxxxxx",
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "UserIdGroupPairs": []
                }
            ],
            "Tags": [
                {
                    "Key": "aws:cloud9:owner",
                    "Value": "XXXXXXXXXXXXXXXXXXXXX:john"
                },
                {
                    "Key": "aws:cloudformation:stack-name",
                    "Value": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                },
                {
                    "Key": "aws:cloud9:environment",
                    "Value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                },
                {
                    "Key": "aws:cloudformation:logical-id",
                    "Value": "InstanceSecurityGroup"
                },
                {
                    "Key": "aws:cloudformation:stack-id",
                    "Value": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
                }
            ],
            "VpcId": "vpc-xxxxxxxx"
        }
    ]
}

EC2 インスタンスも同様。

Terminal

aws describe-instances --filters 'Name=tag-key,Values=Name' 'Name=tag-value,Values=aws-cloud9-foo-*'

{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-0872d0e3184cfc976",
                    "InstanceId": "i-xxxxxxxxxxxxxxxxx",
                    "InstanceType": "t2.micro",
                    "LaunchTime": "2019-07-14T14:59:58.000Z",
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "Placement": {
                        "AvailabilityZone": "ap-northeast-1a",
                        "GroupName": "",
                        "Tenancy": "default"
                    },
                    "PrivateDnsName": "ip-172-31-40-231.ap-northeast-1.compute.internal",
                    "PrivateIpAddress": "172.31.40.231",
                    "ProductCodes": [],
                    "PublicDnsName": "ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com",
                    "PublicIpAddress": "00.000.000.000",
                    "State": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "StateTransitionReason": "",
                    "SubnetId": "subnet-xxxxxxxx",
                    "VpcId": "vpc-xxxxxxxx",
                    "Architecture": "x86_64",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "AttachTime": "2019-07-14T14:59:59.000Z",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-xxxxxxxxxxxxxxxxx"
                            }
                        }
                    ],
                    "ClientToken": "aws-c-Insta-XXXXXXXXXXXX",
                    "EbsOptimized": false,
                    "EnaSupport": true,
                    "Hypervisor": "xen",
                    "NetworkInterfaces": [
                        {
                            "Association": {
                                "IpOwnerId": "amazon",
                                "PublicDnsName": "ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com",
                                "PublicIp": "00.000.000.000"
                            },
                            "Attachment": {
                                "AttachTime": "2019-07-14T14:59:58.000Z",
                                "AttachmentId": "eni-attach-xxxxxxxxxxxxxxxxx",
                                "DeleteOnTermination": true,
                                "DeviceIndex": 0,
                                "Status": "attached"
                            },
                            "Description": "",
                            "Groups": [
                                {
                                    "GroupName": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-InstanceSecurityGroup-XXXXXXXXXXXXX",
                                    "GroupId": "sg-xxxxxxxxxxxxxxxxx"
                                }
                            ],
                            "Ipv6Addresses": [],
                            "MacAddress": "xx:xx:xx:xx:xx:xx",
                            "NetworkInterfaceId": "eni-xxxxxxxxxxxxxxxxx",
                            "OwnerId": "000000000000",
                            "PrivateDnsName": "ip-172-31-40-231.ap-northeast-1.compute.internal",
                            "PrivateIpAddress": "172.31.40.231",
                            "PrivateIpAddresses": [
                                {
                                    "Association": {
                                        "IpOwnerId": "amazon",
                                        "PublicDnsName": "ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com",
                                        "PublicIp": "00.000.000.000"
                                    },
                                    "Primary": true,
                                    "PrivateDnsName": "ip-172-31-40-231.ap-northeast-1.compute.internal",
                                    "PrivateIpAddress": "172.31.40.231"
                                }
                            ],
                            "SourceDestCheck": true,
                            "Status": "in-use",
                            "SubnetId": "subnet-xxxxxxxx",
                            "VpcId": "vpc-xxxxxxxx"
                        }
                    ],
                    "RootDeviceName": "/dev/xvda",
                    "RootDeviceType": "ebs",
                    "SecurityGroups": [
                        {
                            "GroupName": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-InstanceSecurityGroup-XXXXXXXXXXXXX",
                            "GroupId": "sg-xxxxxxxxxxxxxxxxx"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Tags": [
                        {
                            "Key": "aws:cloudformation:logical-id",
                            "Value": "Instance"
                        },
                        {
                            "Key": "Name",
                            "Value": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                        },
                        {
                            "Key": "aws:cloud9:environment",
                            "Value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                        },
                        {
                            "Key": "aws:cloudformation:stack-id",
                            "Value": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
                        },
                        {
                            "Key": "aws:cloud9:owner",
                            "Value": "XXXXXXXXXXXXXXXXXXXXX:john"
                        },
                        {
                            "Key": "aws:cloudformation:stack-name",
                            "Value": "aws-cloud9-foo-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                        }
                    ],
                    "VirtualizationType": "hvm",
                    "CpuOptions": {
                        "CoreCount": 1,
                        "ThreadsPerCore": 1
                    }
                }
            ],
            "OwnerId": "000000000000",
            "RequesterId": "000000000000",
            "ReservationId": "r-xxxxxxxxxxxxxxxxx"
        }
    ]
}

いずれもタグに Cloud9 environment の ID が入っているのでフィルタリングはしやすい。

Cloud9 environment の menbership について学ぶ

AWS マネジメントコンソールから Cloud9 environment を作成した場合は現在の IAM ユーザやロールの ARN が Owner として設定されるようになっている。

Terminal

aws cloud9 describe-environments \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Result

{
    "environments": [
        {
            "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "name": "AWS Management Console",
            "description": "",
            "type": "ec2",
            "arn": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "ownerArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john"
        }
    ]
}

上記の Cloud9 environment の membership がどうなっているか確認してみる。

Terminal

aws cloud9 describe-environment-memberships \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Result

{
    "memberships": [
        {
            "permissions": "owner",
            "userId": "XXXXXXXXXXXXXXXXXXXXX:john",
            "userArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john",
            "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "lastAccess": 1562846115.0
        }
    ]
}

memberships が配列になっていることからもわかるが membership には owner 以外に read-onlyread-write といった権限で複数のユーザを登録することができるようになっている。

Cloud9 environment と membership の関連性

Cloud9 environment の権限には ownerread-onlyread-write の 3 種類がある。AWS マネジメントコンソールから Cloud9 environment を作成した場合、owner には現在の IAM ユーザやロールが設定される。owner は当然のことながら変更や削除などすべての操作を行うことができる。

Cloud9 environment には membership というものがあり、この membership をカスタマイズすることで environment を他のユーザと共有できるようになっている。現状の AWS マネジメントコンソールには membership を操作する画面は無く、Cloud9 IDE 内の共有設定で行うようになっている。

f:id:mattintosh4:20190712195322p:plain
AWS Cloud9 IDE

Cloud9 environment を AWS マネジメントコンソール、Terraform、AWS CLI からownerArn を指定せずにそれぞれ作成すると以下のようになる。なお、AWS マネジメントコンソールでは ownerArn の指定方法が無いため Owner には自動的に現在のユーザに設定される。

{
    "environments": [
        {
            "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "name": "AWS Management Console",
            "description": "",
            "type": "ec2",
            "arn": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "ownerArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john"
        },
        {
            "id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
            "name": "Terraform",
            "description": "",
            "type": "ec2",
            "arn": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
            "ownerArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/1562929437597457834"
        },
        {
            "id": "cccccccccccccccccccccccccccccccc",
            "name": "AWS CLI",
            "description": "",
            "type": "ec2",
            "arn": "arn:aws:cloud9:ap-northeast-1:000000000000:environment:cccccccccccccccccccccccccccccccc",
            "ownerArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/botocore-session-1562929475"
        }
    ]
}

それぞれの ownerArn を見てみると Terraform ではナノ秒タイムスタンプ、AWS CLI では botocore-session- 接頭辞にタイムスタンプが自動的に設定されている。これらの違いを AWS マネジメントコンソールで確認してみる。

まずは「Your environments」を見てみると AWS マネジメントコンソールで作成した Cloud9 environment が表示されている。自分で作成したので Permissions は Owner となっている。作成したはずの「Terraform」や「AWS CLI」は無い。

f:id:mattintosh4:20190712202037p:plain
AWS Cloud9

「Shared with you」を飛ばして「Account environments」を見てみる。先程は無かった「Terraform」と「AWS CLI」も表示されている。

f:id:mattintosh4:20190712202423p:plain
AWS Cloud9

ではこの「Terraform」や「AWS CLI」が使えるのかというのを「Open IDE」を押して試してみるがアクセス権が無いと言われる。

f:id:mattintosh4:20190712202938p:plain
AWS Cloud9

IDE を開くことができないので「Terraform」と「AWS CLI」は AWS マネジメントコンソールから共有設定をすることができず、AWS CLI から設定することになる。しかし、AWS CLI のロールはオーナーではない membership への DeleteEnvironmentMembership 権限が無いので後述する「membership の削除」で問題が発生することがある。

フローにしてみると下記のようになる。

f:id:mattintosh4:20190713012300p:plain
AWS Cloud9

自身が Cloud9 environment の Owner であれば AWS CLI から追加した membership を Cloud9 IDE から削除することができるが、最も困るのが Terraform で owner_arn を未指定で作成してしまった場合。Owner が Terraform で作成した ARN になっているので自身を read-write で membership を追加したとしても Cloud9 IDE に共有設定が表示されないので membership 操作が一切できない。

membership の追加、更新、削除

Cloud9 environment の ID を調べ方

作成した Cloud9 environment の ID を控え忘れてしまった場合は AWS マネジメントコンソールで「Open IDE」や「View Details」、「Edit」を開けば URL に ID が含まれているのでそれをコピーしてもいい。

AWS CLI では list-environments サブコマンドで ID の一覧を表示することができるが、この結果を describe-environments に渡さないと名前がわからない。

Terminal

aws cloud9 list-environments

Result

{
    "environmentIds": [
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
        "cccccccccccccccccccccccccccccccc"
    ]
}

一つずつ調べるのは面倒だが list-environments の結果を --query オプションで整形して describe-environments --environment-ids の引数に渡せば名前付きで一覧を取り出すことができる。

Terminal

aws cloud9 describe-environments \
    --environment-ids $(aws cloud9 list-environments --query "environmentIds" --output text) \
    --query "environments[].[id, name]" \
    --output text

Result

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa        AWS Management Console
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb        Terraform
cccccccccccccccccccccccccccccccc        AWS CLI

membership を追加する

membership の追加には create-environment-membership サブコマンドを使う。ここでは例として IAM ユーザである aliceread-only で追加する。

Terminal

aws cloud9 create-environment-membership \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
    --user-arn arn:aws:iam::000000000000:user/alice \
    --permissions read-only

Result

{
    "membership": {
        "permissions": "read-only",
        "userId": "YYYYYYYYYYYYYYYYYYYYY",
        "userArn": "arn:aws:iam::000000000000:user/alice",
        "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    }
}

describe-environment-memberships で確認すると aliceread-only で追加されていることがわかる。

Terminal

aws cloud9 describe-environment-memberships \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Result

{
    "memberships": [
        {
            "permissions": "read-only",
            "userId": "YYYYYYYYYYYYYYYYYYYYY",
            "userArn": "arn:aws:iam::000000000000:user/alice",
            "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        },
        {
            "permissions": "owner",
            "userId": "XXXXXXXXXXXXXXXXXXXXX:john",
            "userArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john",
            "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "lastAccess": 1562920538.0
        }
    ]
}

membership を更新する

membership の更新には update-environment-membership サブコマンドを使う。

ここでは上で追加した alice の権限を read-only から read-write に変更する。

Terminal

aws cloud9 update-environment-membership \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
    --user-arn arn:aws:iam::000000000000:user/alice \
    --permissions read-write

Result

{
    "membership": {
        "permissions": "read-write",
        "userId": "YYYYYYYYYYYYYYYYYYYYY",
        "userArn": "arn:aws:iam::000000000000:user/alice",
        "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    }
}

再び describe-environment-memberships で確認すると alice の権限が read-write に変更されていることがわかる。

Terminal

aws cloud9 describe-environment-memberships \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Result

{
    "memberships": [
        {
            "permissions": "read-write",
            "userId": "YYYYYYYYYYYYYYYYYYYYY",
            "userArn": "arn:aws:iam::000000000000:user/alice",
            "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        },
        {
            "permissions": "owner",
            "userId": "XXXXXXXXXXXXXXXXXXXXX:john",
            "userArn": "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john",
            "environmentId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "lastAccess": 1562920538.0
        }
    ]
}

membership を削除する

membership の削除には delete-environment-membership サブコマンドを使う。

成功した場合は何も表示されない。

Terminal

aws cloud9 delete-environment-membership \
    --environment-id aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
    --user-arn arn:aws:iam::000000000000:user/alice

AccessDeniedException の例

先に説明したように AWS マネジメントコンソールで Cloud9 environment を作成した場合、AWS CLI からの操作には DeleteEnvironmentMembership 権限が無いためエラーになる。

Result

An error occurred (AccessDeniedException) when calling the DeleteEnvironmentMembership operation:
User arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/botocore-session-1562923366
is not authorized to perform: cloud9:DeleteEnvironmentMembership on resource: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Cloud9 と Terraform

Terraform v0.12.1

Terraform で Cloud9 を扱う場合は aws_cloud9_environment_ec2 リソースを使用する。現状では Cloud9 に関連するリソースはこれしか無い。

aws_cloud9_environment_ec2 を使うときの注意点

Cloud9 envionment の membership の説明に書いたとおり、owner_arn の指定を忘れると membership の操作ができないばかりか Cloud9 IDE に入ることすらできないので(使い方によるが)指定しておいた方が無難。

aws_cloud9_environment_ec2 に変更を加えた場合、大抵は destroy される。automatic_stop_time_minutes は modify になりそうだが、これも destroy の対象なので自動シャットダウンの時間を変更したければ Cloud9 IDE から変更する必要がある。

modify になるもの

  • name を変更する
  • description を変更する

destroy になるもの

  • instance_type を変更する
  • automatic_stop_time_minutes を設定(never から 30 など)または変更(30 から 60 など)する
  • owner_arn を設定または変更する

Terraform による Cloud9 environment の作成

nameinstance_type だけ指定すれば Cloud9 environment を作成することができる。

aws_cloud9.tf

resource "aws_cloud9_environment_ec2" "foo" {
  // STEP 1
  name          = "Terraform"
  instance_type = "t2.micro"
}

Terminal

terraform apply --target aws_cloud9_environment_ec2.foo
terraform state show     aws_cloud9_environment_ec2.foo

owner_arn にはユーザ名としてタイムスタンプが設定される。

# aws_cloud9_environment_ec2.foo: 
resource "aws_cloud9_environment_ec2" "foo" {
    arn           = "arn:aws:cloud9:ap-northeast-1:000000000000:environment:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    id            = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    instance_type = "t2.micro"
    name          = "foo"
    owner_arn     = "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/1562844915108062971"
    type          = "ec2"
}

STEP 2: owner_arn の指定

先程の TF ファイルを変更して owner_arn を追記する。Terraform に限らずだが owner の変更は出来ないため同一名の Cloud9 environment を作成する場合は再構築する必要がある。

aws_cloud9.tf

resource "aws_cloud9_environment_ec2" "foo" {
  // STEP 1
  name          = "foo"
  instance_type = "t2.micro"
  // STEP 2
  owner_arn     = "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john"
}

Terminal

terraform apply --target aws_cloud9_environment_ec2.foo
terraform state show     aws_cloud9_environment_ec2.foo

terraform state show で確認すると owner_arn が指定したとおりに設定されているのがわかる。

# aws_cloud9_environment_ec2.foo: 
resource "aws_cloud9_environment_ec2" "foo" {
    arn           = "arn:aws:cloud9:ap-northeast-1:000000000000:environment:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
    id            = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
    instance_type = "t2.micro"
    name          = "foo"
    owner_arn     = "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john"
    type          = "ec2"
}

STEP 3: automatic_stop_time_minutes を指定する

Cloud9 ではインアクティブな状態が続いたときに自動的に EC2 インスタンスを停止させることができる機能が用意されている。aws_cloud9_environment_ec2 リソースでは automatic_stop_time_minutes という引数(数値型)で指定する。未指定の場合は AWS CLI 同様に never(停止しない)となる。destroy が発生するので「時間を変更したいけれど Cloud9 environment は壊したくない」という場合は IDE を開いて「AWS Cloud9 > Pereferences > PROJECT SETTINGS > EC2 Instance」で設定を変更する。なお、AWS マネジメントコンソールからは変更できない。

aws_cloud9.tf

resource "aws_cloud9_environment_ec2" "foo" {
  // STEP 1
  name                        = "foo"
  instance_type               = "t2.micro"
  // STEP 2
  owner_arn                   = "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john"
  // STEP 3
  automatic_stop_time_minutes = 30
}

Terminal

terraform apply --target aws_cloud9_environment_ec2.foo
terraform state show     aws_cloud9_environment_ec2.foo

指定した場合は下記のように属性と値が表示される。Q & A に書いておくが設定によっては IDE 上で確認できる値と一致しなくなる。指定しなかった場合は自動的に never となり automatic_stop_time_minutes 属性は出てこない。

Result

# aws_cloud9_environment_ec2.foo: 
resource "aws_cloud9_environment_ec2" "foo" {
    arn                         = "arn:aws:cloud9:ap-northeast-1:000000000000:environment:cccccccccccccccccccccccccccccccc"
    automatic_stop_time_minutes = 30
    id                          = "cccccccccccccccccccccccccccccccc"
    instance_type               = "t2.nano"
    name                        = "bar"
    owner_arn                   = "arn:aws:sts::000000000000:assumed-role/OrganizationAccountAccessRole/john"
    type                        = "ec2"
}

EIP の設定やセキュリティグループのカスタマイズの自動化はできるのか

Cloud9 envionment には EIP の設定が無いので自動シャットダウンが行われればパブリック IP アドレスは変わってしまうし、セキュリティグループは自動作成以外の選択肢が無いのでインバウンドルールを追加しないと本来の「踏み台」としては使えない。

しかし、Cloud9 で EC2 インスタンスを作成してもステータスには EC2 インスタンスの詳細情報は含まれていない。これは AWS CLI を使っても同じである。EC2 インスタンスやセキュリティグループは CloudFormation によって作成されているので Name タグには aws-cloud9-環境名-環境ID という書式で名前が設定されている。CloudFormation の aws:cloud9:environment タグにも Cloud9 environment の ID が入っているのでここからリソースを検索することもできるだろう。しかし、CloudFormation のスタックが Terraform の管理外で作成されているので変数呼び出しができない。

EC2 インスタンスの作成を通常通り行い、そちらで Cloud9 IDE のインストールと EIP やセキュリティグループを設定したあとに Cloud9 に SSH タイプで追加すれば…という方法も思いつくが残念ながらいまのところ Terraform には aws_cloud9_environment_ssh というリソースは存在しない。

従って、Cloud9 で EC2 インスタンスを新規に作成する場合は「踏み台」として使うための設定の自動化は簡単ではないと思われる。

Try & Result

Try: owner_arn を指定し忘れたのだが Cloud9 IDE を使いたい

AWS CLIcloud9 create-environment-membership で使用するユーザを membership に追加すればいい。ただし、Cloud9 IDE に membership の設定が表示されず GUI から membership の編集や削除ができないなどの制限があるので潔く作り直したほうがよい。

Try: automatic_stop_time_minutes に適当な値(たとえば 45 など)を設定するとどうなるか

terraform show では設定した通りの値が入っているが Cloud9 IDE で確認してみると切り上げられてプリセット値に設定されていた。(45 の場合であれば 1 時間)

Try: automatic_stop_time_minutes に明示的に never を指定するにはどうするのか

数値型なので automatic_stop_time_minutes = 0 と指定すれば never になる。

まとめ

一般的な「踏み台」として使わずに Cloud9 IDESSH ログイン用のスポットとして使う分にはいいと思うが、リモートサーバにログインするための秘密鍵を配置する必要があるなどいくつかの手間は残る。

個人的にはシェルのキーバインドを多用するので Ctrl + W(1単語前を消す)なんて押そうものならタブが落ちてしまうため Cloud9 IDE 上のターミナルは少々使いにくかったりする。

フロントの開発をやっているエンジニアさん相手には Proxy Jump の説明をするのも一苦労だったりするので AWS アカウントだけあれば使えるというのは便利なのかもしれない。しかし、プロジェクトで複数の人間が同じ Cloud9 IDE を使う場合はあまり向かないと思う。というのも、Cloud9 IDE を共有したとして現状ではそのログイン履歴を記録する方法が無いように思えるし、Linux システムのユーザ切り替えも行われない。これは例えば VNC などで画面共有をしているのとあまり変わらない。便利ではあるが、誰が SSH のコマンドを発行したのかわからないのは内部セキュリティ的にあまりよろしく無いように思える。

他のプロジェクトが Cloud9 をどのように SSH の踏み台として使っているのかは知らないがベストプラクティス的なものが教えてもらいたいものである。

logrotate で複数ファイルの指定

ワイルドカード使えるは知ってるけど複数パス同時指定できるかどうか知らなかったので。単純にスペースとか改行とかで区切ればいいようだ。

/tmp/access.log
/tmp/access_custom.log
/tmp/cache.log
{
    weekly
    compress
    compresscmd /bin/bzip2
    missingok
    rotate 3
    postrotate
    killall -HUP /opt/local/squid/sbin/squid
    endscript
}

logrotate のオプションを確認。

Usage: logrotate [OPTION...] <configfile>
  -d, --debug               Don't do anything, just test (implies -v)
  -f, --force               Force file rotation
  -m, --mail=command        Command to send mail (instead of `/usr/bin/mail')
  -s, --state=statefile     Path of state file
  -v, --verbose             Display messages during rotation
  -l, --log=STRING          Log file or 'syslog' to log to syslog
      --version             Display version information

Help options:
  -?, --help                Show this help message
      --usage               Display brief usage message

-dデバッグオプションを付けてチェック。

logrotate -d -f /etc/logrotate.d/squid

ログを見ると considering log で3つ出てくる。

:
中略
:
rotating pattern: /tmp/access.log
/tmp/access_custom.log
/tmp/cache.log
 weekly (3 rotations)
empty log files are rotated, old logs are removed
considering log /tmp/access.log
Creating new state
  Now: 2019-07-09 15:57
  Last rotated at 2019-07-09 15:00
  log does not need rotating (log has been already rotated)
considering log /tmp/access_custom.log
Creating new state
  Now: 2019-07-09 15:57
  Last rotated at 2019-07-09 15:00
  log does not need rotating (log has been already rotated)
considering log /tmp/cache.log
Creating new state
  Now: 2019-07-09 15:57
  Last rotated at 2019-07-09 15:00
  log does not need rotating (log has been already rotated)

以上