GCEのOS Loginの話

GCE インスタンスの `sshd_config` にはこんなのが書かれていることがある。

（以下、適当にUbuntuインスタンスで検証）
```ssh:/etc/ssh/sshd_config
#### Google OS Login control. Do not edit this section. ####
AuthorizedKeysCommand /usr/bin/google_authorized_keys
AuthorizedKeysCommandUser root
#### End Google OS Login control section. ####
```

なんぞこれ、というお話。

# OS Login

ご存知のようにGCEインスタンスには [OS Login](https://cloud.google.com/compute/docs/oslogin) なるものが存在する。
このおかげでインスタンス毎にわざわざアカウントと鍵を登録する必要がないわけだが、`sshd` 的には鍵を取る方法が必要なので何らかの細工がしてある。
それに使ってるのが `AuthorizedKeysCommand` 項目に指定されてある `google_authorized_keys` というツール。

https://man.openbsd.org/sshd_config#AuthorizedKeysCommand

> #### AuthorizedKeysCommand
> Specifies a program to be used to look up the user's public keys. The program must be owned by root, not writable by group or others and specified by an absolute path. Arguments to AuthorizedKeysCommand accept the tokens described in the TOKENS section. If no arguments are specified then the username of the target user is used.
The program should produce on standard output zero or more lines of authorized_keys output (see AUTHORIZED_KEYS in sshd(8)). AuthorizedKeysCommand is tried after the usual AuthorizedKeysFile files and will not be executed if a matching key is found there. By default, no AuthorizedKeysCommand is run.

このコマンド、トラブルシューティングでも使われている。

https://cloud.google.com/compute/docs/troubleshooting/troubleshoot-os-login#query-specific-user

`/usr/bin/google_authorized_keys USERNAME` をインスタンス上で実行すると、鍵が返ってくる。

# `google_authorized_keys` のやってること

これは普通にGitHubの `GoogleCloudPlatform/guest-oslogin` にある。

https://github.com/GoogleCloudPlatform/guest-oslogin/blob/master/README.md#authorized-keys-command

> ### Authorized Keys Command
> The google_authorized_keys binary is designed to be used with the sshd AuthorizedKeysCommand option in sshd_config(5). It does the following:
> 
> - Reads the user's profile information from the metadata server:
>   ```
>   http://metadata.google.internal/computeMetadata/v1/oslogin/users?username=<username>
>   ```
> - Checks to make sure that the user is authorized to log in:
>   ```
>    http://metadata.google.internal/computeMetadata/v1/oslogin/authorize?email=<user_email>&policy=login
>   ```
> - If the check is successful, returns the SSH keys associated with the user for use by sshd. Otherwise, exits with an error code.

ということで、GCEインスタンスから `metadata.google.internal` にアクセスすれば普通に鍵が取れる仕様になっている。
これを見る限り、公開鍵認証前提なんだろうなという印象を受ける。

ちなみにコードはこの辺

https://github.com/GoogleCloudPlatform/guest-oslogin/blob/master/src/authorized_keys/authorized_keys.cc

```cpp:src/authorized_keys/authorized_keys.cc
  std::stringstream url;
  url << kMetadataServerUrl << "users?username=" << UrlEncode(argv[1]);
  string user_response;
  long http_code = 0;
  if (!HttpGet(url.str(), &user_response, &http_code) ||
      user_response.empty() || http_code != 200) {
    if (http_code == 404) {
      // Return 0 if the user is not an oslogin user. If we returned a failure
      // code, we would populate auth.log with useless error messages.
      // This exits successfully but prints no keys.
      return 0;
    }
    return 1;
  }
```
```cpp:src/authorized_keys/authorized_keys.cc
  url.str("");
  url << kMetadataServerUrl << "authorize?email=" << UrlEncode(email)
      << "&policy=login";
  string auth_response;
  if (!HttpGet(url.str(), &auth_response, &http_code) || http_code != 200 ||
      auth_response.empty()) {
    return 1;
  }
  if (!ParseJsonToSuccess(auth_response)) {
    return 1;
  }
```

`oslogin_utils::kMetadataServerUrl` は今のverだと `http://169.254.169.254/computeMetadata/v1/oslogin/` らしい。

https://github.com/GoogleCloudPlatform/guest-oslogin/blob/master/src/include/oslogin_utils.h

```cpp:src/include/oslogin_utils.h
// Metadata server URL.
static const char kMetadataServerUrl[] =
    "http://169.254.169.254/computeMetadata/v1/oslogin/";
```