vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

Ansible include_tasks で become_user

include_tasks を使用した時に読み込んだタスク全てに become 指定するにはどうするのかを調べたメモ。

バージョンにより挙動は変わりそうですが、 ver 2.9.5 時点では以下の挙動のようです。

include_tasks に become は使用できないので、 読み込まれるタスク側で block を使用して全体に適用することになります。

実行例

id と whoami で実行ユーザを確認します。 sub2.yml を include_tasks で読み込みます。

  • main.yml
---
- hosts: all
  tasks:
   ### tasks
   - name: task1
     command: id
     register: result

   - name: task1 result
     debug: var=result.stdout

   - name: task2
     command: whoami
     register: result

   - name: task2 result
     debug: var=result.stdout

   ### import_tasks
   - name: sub1
     import_tasks: sub1.yml
     tags: ["sub1"]
     become: yes

   - name: sub1
     import_tasks: sub1.yml
     tags: ["sub1"]
     become: yes
     become_user: cwagent

   ### include_tasks (loop)
   - name: sub2
     include_tasks: sub2.yml
     with_items:
       - "root"
       - "cwagent"
     loop_control:
       loop_var: loop_item
     tags: ["sub2"]
  • sub1.yml
- name: sub1_task1
  command: id
  register: result

- name: sub1_task1 result
  debug: var=result.stdout

- name: sub1_task2
  command: whoami
  register: result

- name: sub1_task2 result
  debug: var=result.stdout
  • sub2.yml
- block:

  - name: sub2_item
    debug: var=loop_item

  - name: sub2_task1
    command: id
    register: result

  - name: sub2_task1 result
    debug: var=result.stdout

  - name: sub2_task2
    command: whoami
    register: result

  - name: sub2_task2 result
    debug: var=result.stdout

  become: yes
  become_user: "{{ loop_item }}"
  tags: ["sub2"]

実行結果

$ ansible-playbook -i hosts main.yml

PLAY [all] ******************************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [test-instance]

TASK [task1] ****************************************************************************
changed: [test-instance]

TASK [task1 result] *********************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal)"
}

TASK [task2] ****************************************************************************
changed: [test-instance]

TASK [task2 result] *********************************************************************
ok: [test-instance] => {
    "result.stdout": "ec2-user"
}

TASK [sub1_task1] ***********************************************************************
changed: [test-instance]

TASK [sub1_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=0(root) gid=0(root) groups=0(root)"
}

TASK [sub1_task2] ***********************************************************************
changed: [test-instance]

TASK [sub1_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "root"
}

TASK [sub1_task1] ***********************************************************************
[WARNING]: Unable to use /home/cwagent/.ansible/tmp as temporary directory, failing back
to system: [Errno 13] Permission denied: '/home/cwagent'
changed: [test-instance]

TASK [sub1_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=995(cwagent) gid=993(cwagent) groups=993(cwagent)"
}

TASK [sub1_task2] ***********************************************************************
changed: [test-instance]

TASK [sub1_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "cwagent"
}

TASK [sub2] *****************************************************************************
included: /private/tmp/ansible-test/sub2.yml for test-instance
included: /private/tmp/ansible-test/sub2.yml for test-instance

TASK [sub2_item] ************************************************************************
ok: [test-instance] => {
    "loop_item": "root"
}

TASK [sub2_task1] ***********************************************************************
changed: [test-instance]

TASK [sub2_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=0(root) gid=0(root) groups=0(root)"
}

TASK [sub2_task2] ***********************************************************************
changed: [test-instance]

TASK [sub2_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "root"
}

TASK [sub2_item] ************************************************************************
ok: [test-instance] => {
    "loop_item": "cwagent"
}

TASK [sub2_task1] ***********************************************************************
changed: [test-instance]

TASK [sub2_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=995(cwagent) gid=993(cwagent) groups=993(cwagent)"
}

TASK [sub2_task2] ***********************************************************************
changed: [test-instance]

TASK [sub2_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "cwagent"
}

PLAY RECAP ******************************************************************************
test-instance              : ok=25   changed=10   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

import_tasks と include_tasks について

いずれも別ファイルのタスクを読み込む機能ですが、 静的か動的かということで挙動が異なります。 基本的には import 、ループしたい場合は include という感じでしょうか。

list オプションでの確認例

$ ansible-playbook -i hosts main.yml --list-hosts

playbook: main.yml

  play #1 (all): all    TAGS: []
    pattern: ['all']
    hosts (1):
      test-instance
$ ansible-playbook -i hosts main.yml --list-tasks

playbook: main.yml

  play #1 (all): all    TAGS: []
    tasks:
      task1 TAGS: []
      task1 result  TAGS: []
      task2 TAGS: []
      task2 result  TAGS: []
      sub1_task1    TAGS: [sub1]
      sub1_task1 result TAGS: [sub1]
      sub1_task2    TAGS: [sub1]
      sub1_task2 result TAGS: [sub1]
      sub1_task1    TAGS: [sub1]
      sub1_task1 result TAGS: [sub1]
      sub1_task2    TAGS: [sub1]
      sub1_task2 result TAGS: [sub1]
      sub2  TAGS: [sub2]

$ ansible-playbook -i hosts main.yml --list-tags

playbook: main.yml

  play #1 (all): all    TAGS: []
      TASK TAGS: [sub1, sub2]

AWS CloudWatch Dashboard 複製

簡単にコピーしたかったのです。

同一アカウント

マネジメントコンソール上で別名で保存が簡単かと思います。

f:id:htnosm:20190811141000p:plainf:id:htnosm:20190811141008p:plain

別アカウント

CLI を使います。 jq 使います。

# 複製元のAWSアカウントから DashboardBody を取得

$ aws cloudwatch get-dashboard \
--dashboard-name "sample-dashboard" \
--query 'DashboardBody' > sample-dashboard.json


# 複製先のAWSアカウントに対して、取得した JSON でダッシュボード作成

$ aws cloudwatch put-dashboard \
--dashboard-name "sample-dashboard-copy" \
--dashboard-body "$(jq -r . sample-dashboard.json)"

{
    "DashboardValidationMessages": []
}

jq が無い環境では自力で JSON 書式を調整します。
Text Widget で改行使っている等がある場合はその辺りも考慮必要です。 (下記例は考慮していません) 複製してから修正すれば良い訳ですが。

# sed 例
$ aws cloudwatch put-dashboard \
--dashboard-name "sample-dashboard-copy" \
--dashboard-body "$(sed -e 's/\\"/"/g' -e 's/^"//' -e 's/"$//' sample-dashboard.json)"

おまけでワンライナー

$ aws cloudwatch put-dashboard \
--dashboard-name "sample-dashboard-copy" \
--dashboard-body "$(aws cloudwatch get-dashboard \
  --dashboard-name "sample-dashboard" \
  --query 'DashboardBody' | jq -r . )"

dashboard-name を同一名にしてしまうと上書きされるので注意です。

AWS CloudWatch ECSタスク数

普通に公式に記載がありますが、当たり前過ぎて逆に辿り着くのに時間を要したのでメモ。

データが常時報告される何かしらのメトリクス(CPUUtilization等)の SampleCount で、 RUNNING状態のタスク数のみではありますが、簡単に参照できます。 合計(SUM(METRICS()))すればCluster単位でも出せます。

データポイントの数なので、 Period は 1 Minute です。 (保持期間より過去に遡る場合は、延ばした Period 分で除算すれば算出可能)

ECS (Fargate) のタスク数推移を見たかったわけですが、 サードパーティ製監視サービスの統合機能だと、 Running Task だったり DesiredCount だったり、そのものズバリの名前でメトリクスが用意されているので CloudWatchでも同様のメトリクスがあるものと勝手に思い込んでました。

Ansible で AWS Systems Manager パラメータストア (ついでにシークレットマネージャー) から値を取得

Parameter Store

パラメータストア参照は aws_ssm プラグインで行えます。 version 2.5 から実装されているようです。

Requirements 記載の通り、 botocore,boto3 が必要になります。インストールされていない状態だと下記エラーとなります。

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'aws_ssm'. Error was a <class 'ansible.errors.AnsibleError'>, original message: botocore and boto3 are required for aws_ssm lookup."}

DescribeParameters

# ap-northeast-1
+---------------+--------------------+----------------+
|     KeyId     |       Name         |     Type       |
+---------------+--------------------+----------------+
|  alias/aws/ssm|  an1-securestring  |  SecureString  |
|  None         |  an1-string        |  String        |
|  None         |  an1-stringlist    |  StringList    |
+---------------+--------------------+----------------+

# us-west-2
+---------------+--------------------+----------------+
|     KeyId     |       Name         |     Type       |
+---------------+--------------------+----------------+
|  alias/aws/ssm|  uw2-securestring  |  SecureString  |
|  None         |  uw2-string        |  String        |
|  None         |  uw2-stringlist    |  StringList    |
+---------------+--------------------+----------------+

tasks例

存在しないパラメータはエラーにならず空文字で返却されるため、値チェックを入れた方が良さそうです。

  pre_tasks:
    - name: 'set ssm parameter store values'
      set_fact:
        an1:
          string: "{{ lookup('aws_ssm', 'an1-string') }}"
          securestring: "{{ lookup('aws_ssm', 'an1-securestring') }}"
          stringlist: "{{ lookup('aws_ssm', 'an1-stringlist') }}"
          not_exist: "{{ lookup('aws_ssm', 'dummy') }}"
        uw2:
          string: "{{ lookup('aws_ssm', 'uw2-string', region='us-west-2') }}"
          securestring: "{{ lookup('aws_ssm', 'uw2-securestring', region='us-west-2') }}"
          stringlist: "{{ lookup('aws_ssm', 'uw2-stringlist', region='us-west-2') }}"
          not_exist: "{{ lookup('aws_ssm', 'dummy') }}"

    - name: 'check ssm parameter store values'
      debug: msg="check variable {{ item }}"
      failed_when: '{{ item }} == ""'
      ignore_errors: yes
      with_items:
        - "an1.string"
        - "an1.securestring"
        - "an1.stringlist"
        - "an1.not_exist"
        - "uw2.string"
        - "uw2.securestring"
        - "uw2.stringlist"
        - "uw2.not_exist"

  tasks:
    - name: 'output ssm parameter store values'
      debug: var="{{ item }}"
      with_items:
        - "an1.string"
        - "an1.securestring"
        - "an1.stringlist"
        - "an1.not_exist"
        - "uw2.string"
        - "uw2.securestring"
        - "uw2.stringlist"
        - "uw2.not_exist"

実行結果

TASK [set ssm parameter store values] ***************************************************
ok: [test-instance]

TASK [check ssm parameter store values] *************************************************
 [WARNING]: when statements should not include jinja2 templating delimiters such as {{
}} or {% %}. Found: {{ item }} == ""

ok: [test-instance] => (item=an1.string) => {
    "msg": "check variable an1.string"
}
ok: [test-instance] => (item=an1.securestring) => {
    "msg": "check variable an1.securestring"
}
ok: [test-instance] => (item=an1.stringlist) => {
    "msg": "check variable an1.stringlist"
}
failed: [test-instance] (item=an1.not_exist) => {
    "msg": "check variable an1.not_exist"
}
ok: [test-instance] => (item=uw2.string) => {
    "msg": "check variable uw2.string"
}
ok: [test-instance] => (item=uw2.securestring) => {
    "msg": "check variable uw2.securestring"
}
ok: [test-instance] => (item=uw2.stringlist) => {
    "msg": "check variable uw2.stringlist"
}
failed: [test-instance] (item=uw2.not_exist) => {
    "msg": "check variable uw2.not_exist"
}
fatal: [test-instance]: FAILED! => {"msg": "All items completed"}
...ignoring

TASK [output ssm parameter store values] ************************************************
ok: [test-instance] => (item=an1.string) => {
    "an1.string": "Tokyo文字列",
    "item": "an1.string"
}
ok: [test-instance] => (item=an1.securestring) => {
    "an1.securestring": "Tokyo secure文字列",
    "item": "an1.securestring"
}
ok: [test-instance] => (item=an1.stringlist) => {
    "an1.stringlist": "Tokyo リスト1,Tokyo リスト2,Tokyo リスト3",
    "item": "an1.stringlist"
}
ok: [test-instance] => (item=an1.not_exist) => {
    "an1.not_exist": "",
    "item": "an1.not_exist"
}
ok: [test-instance] => (item=uw2.string) => {
    "item": "uw2.string",
    "uw2.string": "Oregon 文字列"
}
ok: [test-instance] => (item=uw2.securestring) => {
    "item": "uw2.securestring",
    "uw2.securestring": "Oregon secure文字列"
}
ok: [test-instance] => (item=uw2.stringlist) => {
    "item": "uw2.stringlist",
    "uw2.stringlist": "Oregon リスト1,Oregon リスト2,Oregon リスト3"
}
ok: [test-instance] => (item=uw2.not_exist) => {
    "item": "uw2.not_exist",
    "uw2.not_exist": ""
}

Secrets Manager

aws_secret プラグインを使う方法と、aws_ssm 経由で取得する方法の2パターンが利用できそうです。

aws_secret

シークレットマネージャー参照は aws_secret プラグインで行えます。 version 2.8 (2019-05-16) から追加されました。

Requirements 記載の通り、 botocore,boto3 が必要になります。インストールされていない状態だと下記エラーとなります。

FAILED! => {"msg": "The lookup aws_secret requires boto3 and botocore."}

近い内に修正されると思いますが、region指定部分で不具合があります。

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'aws_secret'. Error was a <type 'exceptions.KeyError'>, original message: 'Requested entry (plugin_type: lookup plugin: aws_secret setting: region ) was not defined in configuration.'"}

PRされている修正を反映すると、取得できました。

  • ansible/plugins/lookup/aws_secret.py
@@ -14,6 +14,7 @@
   - botocore>=1.10.0
 extends_documentation_fragment:
   - aws_credentials
+  - aws_region
 short_description: Look up secrets stored in AWS Secrets Manager.
 description:
   - Look up secrets stored in AWS Secrets Manager provided the caller

GetSecretValue

+------------------+----------------------------------+
|    Name          |        SecretString              |
+------------------+----------------------------------+
|  dev/test_secret |  {"dev/test_secret":"testtest"}  |
+------------------+----------------------------------+

tasks例

存在しないシークレットの指定はエラーとなります。

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'aws_secret'. Error was a <class 'ansible.errors.AnsibleError'>, original message: Failed to retrieve secret: ResourceNotFoundException(u'An error occurred (ResourceNotFoundException) when calling the GetSecretValue operation: Secrets Manager can\\u2019t find the specified secret.',)"}
  pre_tasks:
    - name: 'set secrets'
      set_fact:
        an1:
          secret1: "{{ lookup('aws_secret', 'dev/test_secret') }}"
  tasks:
    - name: 'output secrets'
      debug: var="{{ item }}"
      with_items:
        - "an1.secret1"
        - "an1.not_exist"

実行結果

TASK [set secrets] **********************************************************************
ok: [test-instance]

TASK [output secrets] *******************************************************************
ok: [test-instance] => (item=an1.secret1) => {
    "an1.secret1": {
        "dev/test_secret": "testtest"
    },
    "ansible_loop_var": "item",
    "item": "an1.secret1"
}

aws_ssm

制限事項がいくつかありますが、SSM 経由でシークレットマネージャの参照が可能ですので、同様に取得できます。

tasks例

予約パス /aws/reference/secretsmanager/ を含めて指定します。

  pre_tasks:
    - name: 'set secrets using ssm parameter store'
      set_fact:
        an1:
          secret: "{{ lookup('aws_ssm', '/aws/reference/secretsmanager/dev/test_secret') }}"
          not_exist: "{{ lookup('aws_ssm', '/aws/reference/secretsmanager/dummy') }}"
  tasks:
    - name: 'output secrets'
      debug: var="{{ item }}"
      with_items:
        - "an1.secret"
        - "an1.not_exist"

実行結果

TASK [set secrets using ssm parameter store] ********************************************
ok: [test-instance]

TASK [output secrets] *******************************************************************
ok: [test-instance] => (item=an1.secret) => {
    "an1.secret": {
        "dev/test_secret": "testtest"
    },
    "ansible_loop_var": "item",
    "item": "an1.secret"
}
ok: [test-instance] => (item=an1.not_exist) => {
    "an1.not_exist": "",
    "ansible_loop_var": "item",
    "item": "an1.not_exist"
}

__NSPlaceholderDate initialize エラー

Mac OS Mojave (10.14.x) で playbook を実行した際に以下のようなエラーが発生しました。

+[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called.
+[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

以下の環境変数を設定することで回避可能です。

export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

High Sierra (10.13.x) からの仕様変更により発生するようです。

Redash REDASH_GOOGLE_APPS_DOMAIN はもう無い

(最新の)公式読みましょう。

To enable automatic user creation who belong to a specific domain name, you can add this domain (or more) in the setting page:

Redash では Google OAuth 認証が利用できますが、 特定のドメインのみ許可する設定は管理画面上で行います。

[Settings] -> [Settings] -> "Allowed Google Apps Domains" f:id:htnosm:20190502031819p:plain


導入に当たり、参考にした情報が古かったようで、 REDASH_GOOGLE_APPS_DOMAIN を使用(紹介)しているパターンが結構多かったです。 反映されないと小一時間悩みました。
既に廃止されています。

Windows版Squid導入あれやこれや

Windows Server 2016 へ Squid を導入します。 (※ プロキシ設定は触れません。)



Squid について

f:id:htnosm:20190119174746p:plain

コンパイルすることでSOCKSの対応もできそうな感じです。(未確認)

4.10 Does Squid support Socks?
We would like to use Squid, but we need it to use socks to connect to the world outside our firewall.

No changes are necessary to use Squid with socks5. Simply add the usual -Dbind=SOCKSbind etc., to the compile line and -lsocks to the link line.

インストールなど

インストール

ダウンロードした squid.msi でインストール。迷う所はありません。各種設定ファイルは C:\Squid\etc\squid\ に置かれます。

インストールが完了すると、デスクトップ上にアイコンが作成されます。

f:id:htnosm:20190119174847p:plain

  • Squid Server Tray
    • サービスの起動停止、設定ファイルへのリンクを選択できる簡易ツール

f:id:htnosm:20190119174908p:plain

サービスではなく、コマンドでの実行も可能です。

C:\Squid\bin>squid.exe -h
Usage: squid [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]
       -a port   Specify HTTP port number (default: 3128).
       -d level  Write debugging to stderr also.
       -f file   Use given config-file instead of
                 /etc/squid/squid.conf
       -h        Print help message.
       -k reconfigure|rotate|shutdown|restart|interrupt|kill|debug|check|parse
                 Parse configuration file, then send signal to
                 running copy (except -k parse) and exit.
       -n name   Specify service name to use for service operations
                 default is: squid.
       -s | -l facility
                 Enable logging to syslog.
       -u port   Specify ICP port number (default: 3130), disable with 0.
       -v        Print version.
       -z        Create missing swap directories and then exit.
       -C        Do not catch fatal signals.
       -D        OBSOLETE. Scheduled for removal.
       -F        Don't serve any requests until store is rebuilt.
       -N        No daemon mode.
       -R        Do not set REUSEADDR on port.
       -S        Double-check swap during rebuild.
       -X        Force full debugging.
       -Y        Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.

サービスは Squid for Windows という名前で作成されます。自動起動も有効化された状態です。

f:id:htnosm:20190119173903p:plain

ファイアウォール設定

squid 自体での接続元制限設定が行なえますが、それとは別にファイアウォール設定の必要があります。 Squid Cache Server ルールが作成されているので、適宜設定します。

f:id:htnosm:20190119173859p:plain

ログローテーション

ログファイルが C:\Squid\var\log\squid に作成されます。 ログローテーションはコマンド実行で行います。

C:\squid\bin> squid -k rotate

デフォルト10世代(ファイル)です。保存数を変更したい場合は設定ファイルに追記します。

logfile_rotate 10

タスクスケジューラ

Squid 固有というわけではないですが、ログローテーションの定期実行のため、スケジュール実行設定を行います。

C:\>schtasks /create /tn logrotate_squid /tr "C:\Squid\bin\squid.exe -k rotate" /sc weekly /ST 00:00 /rl highest /F /NP
SUCCESS: The scheduled task "logrotate_squid" has successfully been created.

f:id:htnosm:20190119174115p:plain

タスクスケジューラの履歴(ログ)

最近のWindowsはタスクスケジューラの履歴取得がデフォルトで無効のようでした。必要に応じて有効化します。

C:\>wevtutil set-log Microsoft-Windows-TaskScheduler/Operational /enabled:true

履歴の実体はイベントビューアーなので、詳細設定(ログ保持量等)はそちらで行います。

  • [Applications and Services Logs] -> [Microsoft] -> [Windows] -> [TaskScheduler] -> [Operational]

f:id:htnosm:20190119175251p:plain

Macで HTTP Proxy 経由のSSH

macOS からWindows を経由して SSH する機会があったため、調査した内容を残しておきます。
Web上で色々情報が見つかったのですが、現在では古い情報も混ざっているため自分用に整理した内容です。

f:id:htnosm:20190115014841j:plain



要件

macOS -> win_proxy(Windows) -> web(Linux)

上記のように直接接続が許可されていない、win_proxy(WindowsProxyサーバ)の背後のweb(Linuxサーバ)に対し、 macOSからSSH接続を行います。

HTTP CONNECT メソッドで接続を確立しトンネルすることで SSH での接続が可能になります。
環境は以下の通りです。

結果

Nmap付属のncatを使用すると最も環境に依存せずに実現可能と思います。

--proxy-type オプションで "http" を指定します。

Specify proxy type ("http" or "socks4" or "socks5")

$ ssh -o ProxyCommand='ncat --proxy-type http --proxy win_proxy:3128 %h %p' -i ~/.ssh/id_rsa ubuntu@web

# ssh config
Host    web
        Hostname        web
        User            ubuntu
        IdentityFile    ~/.ssh/id_rsa
        ProxyCommand ncat --proxy-type http --proxy win_proxy:3128 %h %p
        ServerAliveInterval 10

Linuxでのncコマンド

-X オプションで "connect" を指定します。

Supported protocols are “4” (SOCKS v.4), “5” (SOCKS v.5) and “connect” (HTTPS proxy).
If the protocol is not specified, SOCKS version 5 is used.

ssh ProxyCommand='nc -X connect -x win_proxy:3128 %h %p' -i ~/.ssh/id_rsa ubuntu@web

# ssh config
Host    web
        Hostname        web
        User            ubuntu
        IdentityFile    ~/.ssh/id_rsa
        ProxyCommand nc -X connect -x win_proxy:3128 %h %p
        ServerAliveInterval 10

Macでのncコマンド

macOS 標準搭載のncコマンドでは接続エラーを解消できずでした。

nc: Proxy error: "HTTP/1.1 200 Connection established" 
ssh_exchange_identification: Connection closed by remote host 

間にLinux等を挟む事で無理やり繋ぐ事は可能です。

ssh ProxyCommand='ssh bastion_linux nc --proxy-type http --proxy win_proxy:3128 %h %p' -i ~/.ssh/id_rsa ubuntu@web

# ssh_config
Host    bastion_linux
        Hostname    bastion_linux
        User        hoge

Host    web
        Hostname        web
        User            ubuntu
        IdentityFile    ~/.ssh/id_rsa
        ProxyCommand ssh bastion_linux nc --proxy-type http --proxy win_proxy:3128 %h %p
        ServerAliveInterval 10

調査

以下メモレベルですが、上記Nmap付属のncat使用に至った経緯です。
無駄に長いので折り畳みます。

続きを読む