10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mac × ターミナルWarp × SSH 補完のために設定見直しをした話

Posted at

Macでターミナルは何を利用されていますか?

私は Rust製で高速、AI搭載でコマンド補完やAgent Modeが便利なターミナル「Warp」を使っています!

履歴検索やブロック実行、共有もしやすく、日常のCLI体験が大きく改善されました。
最近は 日本語化 にも対応し、益々使いやすくなりました!

一方で、SSHの設定はどうしていますか?
~/.ssh/config に全案件を書き連ねると巨大化しがちで、差分追跡や再利用性に課題が出ます。

これを解消するために私は conf.d/*.confを分割運用し、ベース設定と個別案件設定を合成する構成にしていました。

ところが、この方式はWarpの補完と相性問題が出ます。
本記事では、その問題点と、実運用のためどのように変更を行ったかを書こうと思います。

そもそもなぜSSH設定を分割管理していたのか?

一番の理由は、単純に config ファイルが肥大化するのを避けたかったからです!

従来の課題

多くの開発者が直面する(かもしれない)SSH設定の問題

  • 1. 巨大化するconfigファイル: 案件が増えるたびに ~/.ssh/config が肥大化
  • 2. 差分追跡の困難: 一つのファイルに全案件が混在し、変更履歴が追いにくい
  • 3. 再利用性の低さ: 案件ごとの設定を他環境に移植しにくい
  • 4. セキュリティリスク: チーム共有時に不要な案件情報まで露出する可能性

分割管理のメリット

# 従来の構成
~/.ssh/config  # 全案件が混在(1000行超えも珍しくない)
# 分割後の構成
~/.ssh/
├── config       # グローバル設定値や共通方針を書き Include conf.d/*
├── conf.d/      # 個別設定を .conf で分割
│   ├── c-limber.conf
│   ├── ec-rent.conf
│   ├── liwoy.conf
│   └── playza.conf
├── secret_keys/ # 鍵とか
│   ├── c-limber/
│   ├── ec-rent/
│   ├── liwoy/
│   └── playza/

この構成により得られた恩恵は...

  • 案件ごとの独立性: 各 .conf ファイルが独立して管理可能
  • 再利用性向上: 必要な設定のみを他環境にコピー可能
  • バージョン管理: gitで個別ファイルの変更履歴を追跡可能

ターミナルWarp × Include conf.d/* の問題

問題の詳細と技術的背景

Include conf.d/* で分割した設定を使うと、WarpのSSH補完が期待どおりにホストを列挙してくれません。

これは既知の問題で、Warp Issue #4072 で報告されています。

結構前に私もぼやいていました。

他のターミナルアプリ(iTerm2等)では正常に動作するかもしれませんが、
Warpでは Include ディレクティブを認識しません。

ターミナルでSSH補完が動作しない というのは、開発者にとって大きなストレスです!

実際にWarpの利用を開始してから最近までは、補完が効かないまま使っていました。
(shellコマンドを独自に書いたりしていましたが、面倒でした...)

解決への道筋

Warp側の Include ディレクティブ未対応という制約を回避するため、
Warp側での対応は待たず、巨大なconfigを生成してしまえば良いのでは?ついでに設定関連も見直せば良いのでは?
ということで、分割ファイルをビルドして単一の ~/.ssh/config を生成する方式に切り替えることにしました!

改善前の構成 ツリー

~/.ssh/
├─ config       # グローバル設定値や共通方針を記載 & Include conf.d/*
├─ conf.d/      # 個別設定を .conf で分割
└─ secret_keys/ # 鍵とか

改善後の構成 ツリー

~/.ssh/
├─ bin/
│  ├─ ssh-proxy-auto           # SSM経由接続などの補助
│  └─ ssm-target               # AWSタグからInstanceId解決
├─ conf.d/                     # 個別設定を .conf で分割
├─ public_keys/                # 1Password用公開鍵とか
├─ secret_keys/                # 従来の鍵とか
├─ config                      # 最終成果物へのシンボリックリンク
├─ config_base                 # グローバル設定値や共通方針を記載
├─ generated_config            # ベース+分割を合成して生成する最終成果物
├─ config -> generated_config  # シンボリックリンク
└─ Makefile                    # config生成を担う

改善の方針

1. Warp補完に対応

単一 config を生成し、Warp操作時に問題なく補完が効くように!
もう面倒なshell実行などとはおさらばしたい!

2. 既存設定を生かすローカル秘密鍵対応

案件別に IdentityFile ~/.ssh/secret_keys/... を行っていた箇所があるので、それはそのまま動かせるように!
xxxx.conf を書き換えて回ることはしたくなかったため、既存設定は生かす方針に!

3. 1Password対応

IdentityAgent を 1Password SSH Agent のソケットに設定
SSH鍵が1Passwordで管理しているものに対して指紋認証でアクセスできるように!

4. AWS SSM併用に対応

bin/ssh-proxy-autobin/ssm-target により、AWS SSM 接続をサポート

改善の詳細

ファイル設置 - Makefile

config 生成を自動化するMakefileを作成しましたしてもらいました!

CONFIG_DIR=$(HOME)/.ssh
CONF_FILES=$(wildcard $(CONFIG_DIR)/conf.d/*.conf)
GENERATED_CONFIG=$(CONFIG_DIR)/generated_config
CONFIG_LINK=$(CONFIG_DIR)/config

.PHONY: config force clean help
.DEFAULT_GOAL := help

help: ## Show this help message
	@echo "Available targets:"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "  %-15s %s\n", $$1, $$2}'

config: $(GENERATED_CONFIG) ## Generate SSH config from base and conf.d files
	@echo "SSH config generated successfully"

$(GENERATED_CONFIG): $(CONFIG_DIR)/config_base $(CONF_FILES)
	@echo "Generating SSH config..."
	awk 'FNR==1 && NR!=1{print ""} {print}' $^ > $@
	chmod 600 $@
	ln -sf $(GENERATED_CONFIG) $(CONFIG_LINK)
	@echo "Config linked to $(CONFIG_LINK)"

force: ## Force regeneration of SSH config
	$(MAKE) --always-make config

clean: ## Remove generated config and link
	rm -f $(GENERATED_CONFIG) $(CONFIG_LINK)
	@echo "Cleaned generated files"

このMakefileの動作:

  1. 依存関係の管理: config_baseconf.d/*.conf の変更を検知
  2. ファイル連結: awk でファイル間に空行を挿入しながら連結(FNR==1 && NR!=1{print ""}
  3. 権限設定: generated_config に適切な権限(600)を設定
  4. シンボリックリンク: configgenerated_config へのリンクに変更
  5. ユーザビリティ: make help で利用可能なターゲット一覧を表示
  6. クリーンアップ: make clean で生成ファイルを削除可能

実際の設定例と運用方法

基本的な設定ファイル構成

グローバル設定(config_base

### Global defaults
Host *

# 1Password SSH Agent
IdentityAgent ~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock

# その他共通設定をこの下に長々と記述

GitHub用設定(conf.d/github.conf

###################################################################
## Github #########################################################

Host github github.com
    HostName github.com
    User git
    IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
    IdentityFile ~/.ssh/public_keys/github/github.pub
    IdentitiesOnly yes

各種案件用既存設定(conf.d/example-project.conf

###################################################################
## Example Project #################################################

# 本番Webサーバー(ubuntuユーザー)
Host example-prod-web
    HostName xxx.xxx.xxx.xxx
    User ubuntu
    IdentityFile ~/.ssh/secret_keys/example/prod-web.pem
    IdentitiesOnly yes
    StrictHostKeyChecking yes
    CheckHostIP yes

# 本番Webサーバー(アプリケーションユーザー)
Host example-prod-app
    HostName xxx.xxx.xxx.xxx
    User app
    IdentityFile ~/.ssh/secret_keys/example/app-key.pem
    IdentitiesOnly yes
    StrictHostKeyChecking yes
    CheckHostIP yes

# 開発サーバー
Host example-dev
    HostName xxx.xxx.xxx.xxx
    User ubuntu
    IdentityFile ~/.ssh/secret_keys/example/dev.pem
    IdentitiesOnly yes
    StrictHostKeyChecking accept-new
    CheckHostIP no

# ステージングサーバー
Host example-staging
    HostName xxx.xxx.xxx.xxx
    User ubuntu
    IdentityFile ~/.ssh/secret_keys/example/staging.pem
    IdentitiesOnly yes
    StrictHostKeyChecking yes
    CheckHostIP yes

1Password利用時の設定(conf.d/example-1p.conf

# 1Passwordを使う場合は、グローバル設定(config_base)で既に設定済み
# IdentityAgent ~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock

# 個別のHost設定では、公開鍵ファイルを指定するだけ
Host example-1p-server
    HostName xxx.xxx.xxx.xxx
    User ubuntu
    IdentityFile ~/.ssh/public_keys/example/example-1p-server.pub
    IdentitiesOnly yes

SSM接続用設定(conf.d/ssm.conf

※まだちゃんと試していません

###################################################################
## AWS SSM ########################################################

# インスタンスID直指定
Host ssm/i-*
    User ec2-user
    ProxyCommand sh -lc 'AWS_PROFILE=prod AWS_REGION=ap-northeast-1 aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters "portNumber=%p" 2>/dev/null'
    StrictHostKeyChecking yes
    CheckHostIP no

# Name タグ指定
Host ssm/name:*
    User ec2-user
    ProxyCommand sh -lc 'AWS_PROFILE=prod AWS_REGION=ap-northeast-1 ~/.ssh/bin/ssm-target ${HOST#ssm/name:} | xargs -I{} aws ssm start-session --target {} --document-name AWS-StartSSHSession --parameters "portNumber=%p" 2>/dev/null'
    StrictHostKeyChecking yes
    CheckHostIP no

日常的な運用

  1. 設定ファイル作成: conf.d/ に新しい .conf ファイルを作成
  2. 設定生成: make config で設定を再生成
  3. 接続テスト: ssh <新しいホスト名> で接続確認

まとめ

  • Warp対応: config_base + conf.d/*.conf をビルドして単一の generated_config を作り、config をそれにリンクする運用で安定
  • 設定管理の複雑さ回避: 巨大化するSSH設定ファイルの管理を分割・統合の仕組みで解決
  • 多様な環境対応: 1PasswordのSSH Agent、AWS SSM連携、案件別鍵運用も同構成で共存可能

Warpを使いながら、SSH設定も効率的に管理したい開発者の方々に、この手法が参考になれば幸いです。

参考リンク

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?