patorashのブログ

方向性はまだない

ansibleでheroku cli経由でherokuに自動ログインする方法

herokuへのメンテナンスを行うための中継サーバの構成をansibleで作っている最中です。

やりたいことはほぼできたのですが、1つだけ課題が残っていました。それは、ansibleでherokuに自動ログインできないことです。今回、それをなんとか自動ログインさせることに成功したので、メモとして残しておきます。

expectモジュールだとNG

herokuへのログインはheroku cliを使えばCUIでできるので、ansibleのexpectモジュールを使ってログインしようとしたのですが、なぜかうまくいきませんでした。 どうも、herokuのパスワードを入力後の改行コードが何故かパスワードの一部として解釈されてしまい、タイムアウトしてしまいました。

NGだったやつを残しておきます。

---
- name: heroku-cliのインストール
  command: sudo sh -c "export PATH=/usr/local/bin:$PATH && curl https://cli-assets.heroku.com/install.sh | sh"
  args:
    creates: /usr/local/bin/heroku

- name: pexpectのインストール
  pip:
    name: pexpect
    executable: pip3.8

- name: Heroku Loginする
  become_user: "{{ user }}"
  expect:
    command: heroku auth:login --interactive
    responses:
      "Email: ": "{{ heroku_email }}"
      "Password: ": "{{ heroku_token }}"
    echo: yes
  environment:
    PATH: "/usr/local/bin:{{ ansible_env.PATH }}"
  no_log: yes

scriptモジュール経由でexpectを使えばOK

入力の自動化はexpectでできるはずなので、もっと具体的に書き込めばいいかなと思い、expectコマンドをインストールして直接使うようにしてみました。

roleのファイルはこれ。 変数でheroku_emailheroku_tokenを渡しています。(2要素認証にしているためパスワードの代わりにトークンを使用) ローカルにscriptがあればいいので、scriptモジュールで指定。argsのexecutableで実行される命令としてexpectを指定しています(デフォルトだとshになる)

---
- name: heroku-cliのインストール
  command: sudo sh -c "export PATH=/usr/local/bin:$PATH && curl https://cli-assets.heroku.com/install.sh | sh"
  args:
    creates: /usr/local/bin/heroku

- name: yumでexpectのインストール
  yum:
    name: expect
    state: present

- name: ローカルから、expectスクリプトを実行してheroku loginする
  become_user: "{{ user }}"
  script: heroku_login.exp
  args:
    executable: /usr/bin/expect
  environment:
    PATH: "/usr/local/bin:{{ ansible_env.PATH }}"
    HEROKU_EMAIL: "{{ heroku_email }}"
    HEROKU_TOKEN: "{{ heroku_token }}"
  changed_when: false

expectスクリプトである、heroku_login.expは、これ。肝は、sendでパスワード文字列を送った後に入れているsleep 1です。

spawn heroku auth:login --interactive
sleep 1
expect "Email: "
send "$env(HEROKU_EMAIL)"
send "\r"
sleep 1
expect "Password: "
send "$env(HEROKU_TOKEN)"
sleep 1
send "\r"
sleep 2
interact

heroku cliは、入力されたパスワード文字列を****という感じに隠してくれるのですが、表示が****になる前に改行コード\rを送ってしまうと、パスワードの1部と解釈されるみたいでした。

そのため、パスワード入力後に1秒のsleepを差し込んで、****に変換されるのを確認した後、改行コードを送るようにしたところ、ログインできました👍