ConoHaではサーバ内でファイアウォールを設定しなくても、VPSの外側でセキュリティグループを設定することで開放ポートを設定することができます。

しかしここで設定できるのはデフォルトで用意されたこれだけです。もうちょっと頑張りたいとき――例えばSSHポートは22番から8022番に変更してアタックされにくくして、FTPは使わないので20/21番は閉じたい、という場合にはブラウザからは操作できません。APIならできます。

大雑把な手順

  1. 新しいセキュリティグループを追加する
  2. セキュリティグループにルールを追加する
  3. ネットワークポートにセキュリティグループを適用する
  4. サーバ内のファイアウォールを設定する
  5. SSHの待ち受けポートを8022番にする

OSはCentOS7.1のイメージを使う前提とします。

1と2はアカウント単位での作業です。VPSを2つ以上作るときでも作業は1回しておけばOKです。3はVPS単位です。4はAPIではありませんが、デフォルトでは22番ぐらいしか開いていませんので作業が必要です。5番を忘れるとネットワークの外側から接続できなくなります。

APIトークンを発行する

まず「APIのログイン」ともいえるトークン発行を行います。

usernameは管理画面の「API」タブにあるAPIユーザ名をコピペします。自分で設定はできません。 passwordは管理画面で事前に設定します。右側の鉛筆アイコンです。 tenantIdも管理画面のAPI情報「テナントID」からコピーします。

パイプで「python -mjson.tool」に渡すことで、jsonの出力を整形して読みやすくしています。実行結果は次のようになります。

$ curl -X POST \
> -H "Accept: application/json" \
> -d '{"auth":{"passwordCredentials":{"username":"gncu12345678","password":"PASSWORDPASSWORDPASSWORD"},"tenantId":"tenantidtenantidtenantidtenantid"}}' \
> https://identity.tyo1.conoha.io/v2.0/tokens \
> | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2592  100  2452  100   140   4163    237 --:--:-- --:--:-- --:--:--  4162
{
    "access": {
        "metadata": {
            (中略)
        },
        "serviceCatalog": [
            (中略)
        ],
        "token": {
            (中略)
            "id": "9999tokenid9999tokenid9999tokeni",
            (中略)
            }
        },
        "user": {
            (中略)
        }
    }
}

これのうちaccess.token.idの値がトークンになります。以降のリクエストヘッダ「X-Auth-Token: 9999tokenid9999tokenid9999tokeni」として指定することで、各APIを使用できます。

新しいセキュリティグループを追加する

追加する前に、現在あるセキュリティグループを確認しましょう。

$ curl -X GET \
> -H "Accept: application/json" \
> -H "X-Auth-Token: 9999tokenid9999tokenid9999tokeni" \
> https://networking.tyo1.conoha.io/v2.0/security-groups \
> | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7496  100  7496    0     0  11431      0 --:--:-- --:--:-- --:--:-- 11426
{
    "security_groups": [
        {
            "description": "default",
            (中略)
        },
        {
            "description": "gncs-ipv4-ssh",
            (中略)
        },
        {
            "description": "gncs-ipv6-ssh",
            (中略)
        },
       (中略)
        }
    ]
}

セキュリティグループを作成します。ブラウザ画面でいうところのチェックボックスに相当するものを追加するわけですが、ブラウザには表示されません。

$ curl -X POST \
> -H "Accept: application/json" \
> -H "X-Auth-Token: 9999tokenid9999tokenid9999tokeni" \
> -d '{"security_group": {"name": "ssh-8022"}}' \
> https://networking.tyo1.conoha.io/v2.0/security-groups \
> | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   809  100   769  100    40    958     49 --:--:-- --:--:-- --:--:--   958
{
    "security_group": {
        "description": "",
        "id": "11112222-3333-4444-5555-666677778888",
        "name": "ssh-8022",
        "security_group_rules": [
            (中略)
        ],
        "tenant_id": "tenantidtenantidtenantidtenantid"
    }
}

セキュリティグループのIDは「11112222-3333-4444-5555-666677778888」です。

セキュリティグループにルールを追加する

セキュリティグループ「11112222-3333-4444-5555-666677778888」にルールを追加します。tcp8022番ポートは受け付ける、というルールになります。

$ curl -X POST \
> -H "Accept: application/json" \
> -H "X-Auth-Token: 9999tokenid9999tokenid9999tokeni" \
> -d '{"security_group_rule": {"direction": "ingress", "ethertype": "IPv4", "security_group_id": "11112222-3333-4444-5555-666677778888", "port_range_min": "8022", "port_range_max": "8022", "protocol": "tcp"}}' \
> https://networking.tyo1.conoha.io/v2.0/security-group-rules \
> | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   526  100   324  100   202    380    237 --:--:-- --:--:-- --:--:--   380
{
    "security_group_rule": {
        "direction": "ingress",
        "ethertype": "IPv4",
        "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        "port_range_max": 8022,
        "port_range_min": 8022,
        "protocol": "tcp",
        "remote_group_id": null,
        "remote_ip_prefix": null,
        "security_group_id": "11112222-3333-4444-5555-666677778888",
        "tenant_id": "tenantidtenantidtenantidtenantid"
    }
}

同様にして80/443番を開けるセキュリティグループも作ります。できたセキュリティグループIDは「99992222-9999-4444-9999-666677779999」とします。

できあがったらもう一度セキュリティグループ一覧を取得し、差分を確認すると完璧です。

ネットワークポートにセキュリティグループを適用する

さて、新しいセキュリティグループをネットワークポートに適用したいわけですが、IPアドレスはわかるもののAPI上のIDはわかりません。一覧を取得して、探し出しましょう。

$ curl -X GET \
> -H "Accept: application/json" \
> -H "X-Auth-Token: 9999tokenid9999tokenid9999tokeni" \
> https://networking.tyo1.conoha.io/v2.0/ports \
> | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2762  100  2762    0     0   4281      0 --:--:-- --:--:-- --:--:--  4275
{
    "ports": [
        {
            (中略)
            "fixed_ips": [
                {
                    "ip_address": "172.21.140.210",
                    "subnet_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
                }
            ],
            "id": "11111111-2222-2222-2222-3333port3333",
            (中略)
        },
        (中略)
        "security_groups": [
            "22222222-4444-4444-6666-666688888888"
        ],
        (中略)
    ]
}

IPに紐づくネットワークポートIDと、ついでに今あるセキュリティグループも分かりました。 今あるセキュリティグループに、先ほどの新しいセキュリティグループを追加した形で上書きします。

$ curl -X PUT \
> -H "Accept: application/json" \
> -H "X-Auth-Token: 9999tokenid9999tokenid9999tokeni" \
> -d '{"port": {"security_groups": ["11112222-3333-4444-5555-666677778888","99992222-9999-4444-9999-666677779999","22222222-4444-4444-6666-666688888888"]}}' \
> https://networking.tyo1.conoha.io/v2.0/ports/11111111-2222-2222-2222-3333port3333 \
> | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   995  100   846  100   149    986    173 --:--:-- --:--:-- --:--:--   986
{
    "port": {
        (中略)
        "security_groups": [
            "11112222-3333-4444-5555-666677778888",
            "22222222-4444-4444-6666-666688888888",
            "99992222-9999-4444-9999-666677779999"
        ],
        "status": "BUILD",
        "tenant_id": "tenantidtenantidtenantidtenantid"
    }
}

これでセキュリティグループの設定が完了しました。

サーバ内のファイアウォールを設定する

セキュリティグループはサーバの外側を守ってくれますが、これに不具合ができないとも限らないので、内側のファイアウォールも同じように必要なだけを開けることとします。

# firewall-cmd --add-port=8022/tcp --zone=public --permanent
# firewall-cmd --add-port=80/tcp --zone=public --permanent
# firewall-cmd --add-port=443/tcp --zone=public --permanent
# firewall-cmd --reload

結果はこんな感じになります。

# firewall-cmd --list-all
public (default, active)
  interfaces: eth0
  sources:
  services: dhcpv6-client ssh
  ports: 80/tcp 443/tcp 8022/tcp
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

sshdの待ち受けポートを8022番に変更

# vi /etc/ssh/sshd_config
# systemctl restart sshd

一緒に操作端末の~/.ssh/configに対象サーバのポートが8022番であることの設定をしておけば、22番以外に変更していることを気にしなくて済むようになります。

API直接でなくneutronコマンドでも可能

この辺の操作はAPIを直接使うのではなくneutronコマンドを使ったほうが楽かもしれません。実際、中の人の連載でもそのようにしています。

http://gihyo.jp/dev/serial/01/conoha/0005?page=2

負荷の増減に合わせてインスタンスを作ったり破棄したりするような、AWS的な仕組みを作るなら手順3以降は自動化する必要があります。その際はAPIのほうが都合がよいかもしれません。

柔軟な運用はfirewalld + ansibleなどで実現したほうがやりやすそうです。しかしインスタンスをAPI経由で作るとデフォルトのセキュリティグループ”default”だけは全アクセス拒否になってしまうので、何かしらの操作は必要になります。自動化するなら避けて通れないところのAPI手順でした。