netbox-config-templates について
NetBox の設定テンプレートとコンテキストデータを扱うリファレンスで、デバイスや仮想マシンの設定を生成する運用担当者や開発者向けです。Jinja2 のレンダリング、コンテキストのマージ規則、API の使い方を説明します。
主な機能
- 01Jinja2 テンプレートのレンダリング
- 02設定コンテキストの割り当てとマージ
- 03デバイスと VM のテンプレート解決
- 04API による設定レンダリング
- 05テンプレートの性能とセキュリティ上の注意
活用シーン
- 01NetBox データからデバイス設定を生成
- 02デバイス階層に沿った設定コンテキストの整理
- 03CI/CD やプロビジョニングでレンダリング API を呼び出す
- 04コンテキストのマージやレンダリング問題の調査
MCP 対応
NetBox MCP サーバーが設定されている場合、デバイスの設定コンテキストを取得してテンプレートのレンダリング結果を確認できます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ netboxlabs/ skills --skill netbox-config-templatesインストール後、Claude Code で/netbox-config-templatesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api-rendering-patterns.mdconfig-context-merging.mdcontext-variables.md詳細
NetBox 設定テンプレート
NetBox の設定テンプレートに関する知識は古くなっている可能性があります。 テンプレートのコンテキスト変数、レンダリング API、設定コンテキストのマージ動作は、リリースごとに変更されます。事前学習済みの知識よりも、情報を取得して確認してください。
情報の取得元
| 情報源 | URL/方法 | 用途 |
|---|---|---|
| 設定テンプレートのドキュメント | https://netboxlabs.com/docs/netbox/features/configuration-rendering/ | テンプレート構文、コンテキスト変数 |
| 設定コンテキストのドキュメント | https://netboxlabs.com/docs/netbox/features/context-data/ | 階層データ、マージ規則 |
| NetBox リポジトリ | https://github.com/netbox-community/netbox | テンプレートのレンダリングに関するソースコード |
| NetBox MCP サーバー | 設定済みの場合 — デバイスの設定コンテキストを取得し、テンプレートのレンダリングをテスト | コンテキストデータの検証 |
NetBox には、Jinja2 ベースの設定レンダリングシステムが組み込まれています。テンプレートを定義し、設定コンテキストを使ってデータを入力すると、API 経由でデバイスごと、または VM ごとの設定をレンダリングできます。このスキルでは、ワークフロー全体を扱います。
このスキルを使用する場面
- NetBox のデータからデバイス/VM の設定を生成する場合
- テンプレートのレンダリング用に設定コンテキスト(階層データ)を設定する場合
- NetBox の設定レンダリングを CI/CD やプロビジョニングのパイプラインに統合する場合
- テンプレートのレンダリングの問題や、設定コンテキストのマージ動作をトラブルシューティングする場合
クイックリファレンス
テンプレートの解決順序(デバイス)
device.config_template → device.role.config_template → device.platform.config_template
最初に一致したテンプレートが使用されます。デバイスごとにレンダリングされるテンプレートは 1 つだけです。VM も同じパターン(ロール → プラットフォーム)に従います。
主要な API エンドポイント
| 操作 | メソッド | エンドポイント |
|---|---|---|
| デバイス設定をレンダリング | POST | /api/dcim/devices/{id}/render-config/ |
| VM 設定をレンダリング | POST | /api/virtualization/virtual-machines/{id}/render-config/ |
| テンプレートを直接レンダリング | POST | /api/extras/config-templates/{id}/render/ |
| 設定テンプレートの CRUD | GET/POST/PUT/PATCH/DELETE | /api/extras/config-templates/ |
| 設定コンテキストの CRUD | GET/POST/PUT/PATCH/DELETE | /api/extras/config-contexts/ |
コンテキスト変数の早見表
デバイス/VM のレンダリング(render-config):
| 変数 | 型 | 説明 |
|---|---|---|
device / virtualmachine | ORM インスタンス | すべての関連情報を含む完全なモデル |
| (設定コンテキストのキー) | さまざま | トップレベルキーとしてマージされた設定コンテキストデータ |
| (POST ボディのキー) | さまざま | レンダリングリクエストとともに送信される追加データ |
汎用レンダリング(config-templates/{id}/render/):
| 変数 | 型 | 説明 |
|---|---|---|
dcim、ipam、virtualization など | モジュールのようなもの | すべての公開 NetBox モデルクラスへのアクセス |
| (POST ボディのキー) | さまざま | レンダリングリクエストとともに送信される追加データ |
詳細については、references/context-variables.md を参照してください。
設定コンテキストシステム
設定コンテキストは、テンプレートに構造化された JSON データを提供します。オブジェクトの属性に基づいて割り当てられ、ウェイト順にマージされます。
割り当てのロジック
オブジェクトが空でない割り当てカテゴリすべてに一致する場合(カテゴリ間は AND)、かつ各カテゴリ内の値のいずれかに一致する場合(カテゴリ内は OR)、設定コンテキストが適用されます。
割り当てカテゴリ:リージョン、サイトグループ、サイト、ロケーション、デバイスタイプ、ロール、プラットフォーム、クラスタタイプ、クラスタグループ、クラスター、テナントグループ、テナント、タグ。
マージ順序
- 一致するアクティブな設定コンテキストをすべて、ウェイトの昇順、次に名前順で適用します
- キーが衝突した場合、ウェイトの高いコンテキストがウェイトの低いコンテキストを上書きします
- ローカルコンテキストデータ(デバイス/VM 自体に保存されたもの)は最後にマージされ、常に優先されます
⚠️ リストはマージではなく置換されます
deepmerge() は辞書を再帰的にマージしますが、辞書以外の値は完全に置換します:
// Weight 100: {"ntp_servers": ["10.0.0.1", "10.0.0.2"]}
// Weight 200: {"ntp_servers": ["10.1.1.1"]}
// Result: {"ntp_servers": ["10.1.1.1"]} ← NOT concatenated
この点を考慮してデータ構造を設計してください。加算的なマージが必要な場合は、一意のキーを持つ辞書を使用してください。
階層の解決
階層モデル(リージョン、サイトグループなど)では、親に割り当てられたコンテキストはすべての子孫にも適用されます。「Americas」リージョンに割り当てられたコンテキストは、「US-East」サブリージョンのデバイスにも一致します。
事前レンダリングキャッシュ(NetBox 4.7+)
4.7 では、統合結果が各デバイス/VM 上で事前レンダリングされ、キャッシュされます。上流で変更(設定コンテキストの作成・編集・削除、または適用されるコンテキストに影響するデバイス/VM 属性の変更)があるとキャッシュは無効化され、ブロッキングしないバックグラウンドジョブによって再レンダリングされます。無効化から再レンダリングまでの間は、読み取り時にオンデマンドでのレンダリングにフォールバックするため、結果が古くなることはありません。マージのセマンティクスに変更はありません。アップグレード後、アップグレードスクリプトが manage.py rebuild_config_context_cache を実行します(デバイス/VM ごとに UPDATE を 1 回実行します。中断して再実行しても安全です)。シグナルを迂回する一括書き込み(queryset.update())ではキャッシュが無効化されないため、その後 rebuild_config_context_cache --force を実行してください。4.5/4.6 では、設定コンテキストは読み取りのたびに計算されます。
マージについて詳しくは、references/config-context-merging.md を参照してください。設定コンテキストのデータモデリングに関するベストプラクティスについては、netbox-data-modeling を参照してください。
テンプレートの作成
デバイスデータへのアクセス
device(または virtualmachine)変数は、完全な Django ORM インスタンスです。
hostname {{ device.name }}
!
{% if device.primary_ip4 %}
ip address {{ device.primary_ip4.address | ipaddr('address') }}
{% endif %}
!
{% for iface in device.interfaces.all() %}
interface {{ iface.name }}
description {{ iface.description | default('', true) }}
{% for ip in iface.ip_addresses.all() %}
ip address {{ ip.address }}
{% endfor %}
{% endfor %}
設定コンテキストデータの使用
設定コンテキストのキーは、トップレベルのテンプレート変数として表示されます。
{% for server in ntp_servers | default([]) %}
ntp server {{ server }}
{% endfor %}
!
{% for server in syslog_servers | default([]) %}
logging host {{ server }}
{% endfor %}
!
{% if snmp_community is defined %}
snmp-server community {{ snmp_community }} RO
{% endif %}
テンプレートの継承(DataSource が必須)
{% extends %} と {% include %} が機能するのは、テンプレートがDataSource(git リポジトリ、S3 など)に保存されている場合のみです。インラインの template_code で定義されたテンプレートからは、ほかのテンプレートを解決できません。
{# Stored in a DataSource alongside base.j2 #}
{% extends 'base.j2' %}
{% block interfaces %}
{% for iface in device.interfaces.all() %}
interface {{ iface.name }}
{% endfor %}
{% endblock %}
テンプレート内の ORM クエリ
デバイスのレンダリングと汎用のレンダリングのどちらでも、NetBox モデルを利用できます。
{# Query prefixes from IPAM #}
{% set mgmt_prefixes = ipam.Prefix.objects.filter(role__slug='management') %}
{% for pfx in mgmt_prefixes %}
ip route {{ pfx.prefix }} Management
{% endfor %}
警告: ORM クエリはサンドボックス化されず、データベースに対して実行されます。大きなテーブルに対する不用意な .all() は処理が遅くなります。クエリの制限はありません。
Jinja2 環境
- テンプレートは SandboxedEnvironment で実行されます — ファイル I/O や任意のインポートはできません
- NetBox の設定では
JINJA_FILTERS(4.7 以降。旧名のJINJA2_FILTERSも引き続き動作しますが、非推奨であり、5.0 で削除されます) /JINJA2_FILTERS(4.5/4.6) を使ってカスタムフィルターを追加できます。4.7 におけるフィルターの優先順位は、低いものから順に、組み込み(env)→ プラグイン登録済み → インスタンスのJINJA_FILTERSです。 - プラグインは Jinja フィルターを登録し、テンプレートコンテキスト変数を注入できます(NetBox 4.7 以降)。
jinja_env.py/register_jinja_filters()およびPluginConfig.get_jinja_context()を使います。手順については netbox-plugin-development を参照してください。プラグインコンテキストはグローバル(オブジェクトごとではありません)であり、dcimのようなアプリラベル名を再利用してはいけません。 - テンプレート内のカスタムオブジェクト(NetBox 4.7 以降、netbox-custom-objects v0.6.1 以降):
custom_objects.<type_name>.filter(device=device)または'<type_name>' | custom_objectsを使うと、内部名でカスタムオブジェクトのタイプを参照できます。4.5/4.6 ではcustom_objectsは存在しません。netbox-custom-objects を参照してください。 - 組み込みの
env()フィルター(NetBox 4.6.2 以降) — システム環境変数の値を返します:{{ 'WEBHOOK_TOKEN_3' | env }}。JINJA_ENVIRONMENT_PARAMS設定リスト(許可する変数名の fnmatch ワイルドカード許可リスト)によって制限されており、一致する名前がない場合はNoneを返します。4.6.1 以前には組み込みのカスタムフィルターはなく、標準の Jinja2 フィルターのみ使用できます。 - テンプレートごとの
environment_paramsで動作をカスタマイズできます(例:undefined: jinja2.StrictUndefined)。ただし、NetBox 4.6.1 以降ではキーが許可リストに登録されている必要があります — 以下を参照してください。
NetBox 4.6.1 以降 —
environment_paramsの許可リスト(CVE-2026-29514)。environment_params(ConfigTemplate と ExportTemplate で共有)経由の修正済み RCE により、受け付けるキー(JINJA_ENV_PARAMS_ALLOWED)が制限されています。許可されるのは、標準の区切り文字/空白/スカラーのパラメーター(trim_blocks、lstrip_blocks、autoescape、keep_trailing_newline、ブロック/コメント/変数の*_string区切り文字など)とundefinedです。ただしundefinedはjinja2.StrictUndefined、jinja2.Undefined、jinja2.ChainableUndefined、jinja2.DebugUndefinedのいずれかでなければなりません。extensions、finalize、loader、bytecode_cacheはブロックされており、これらを設定したテンプレートは拒否されます。 このスキルの例(StrictUndefined、trim_blocks、lstrip_blocks)は引き続き有効です。ブロックされたキーは推奨しないでください。
よくあるベンダーパターン
戦略 1:プラットフォームベースのテンプレート割り当て(推奨)
異なる設定テンプレートを、それぞれ異なるプラットフォームに割り当てます。
| プラットフォーム | 設定テンプレート |
|---|---|
junos | junos-base.j2 |
ios-xe | ios-xe-base.j2 |
eos | eos-base.j2 |
テンプレートは、デバイス → ロール → プラットフォームの順に解決されます。これが最もすっきりした方法です。
戦略 2:単一テンプレート内の条件分岐
{% if device.platform.slug == 'junos' %}
system {
host-name {{ device.name }};
}
{% elif device.platform.slug == 'ios-xe' %}
hostname {{ device.name }}
{% elif device.platform.slug == 'eos' %}
hostname {{ device.name }}
{% endif %}
小さな差異には有効ですが、扱いにくくなります。本番環境では戦略 1 を推奨します。
API レンダリングパターン
デバイス設定をレンダリングする
import requests
NETBOX = "https://netbox.example.com"
TOKEN = "nbt_abc123.xxxxxxxxxxxxxxxx"
headers = {"Authorization": f"Bearer {TOKEN}"}
# Render config for device ID 42
response = requests.post(
f"{NETBOX}/api/dcim/devices/42/render-config/",
headers=headers,
json={}, # optional extra context data
)
response.raise_for_status()
config = response.json()["content"]
JSON でラップされていない生の設定出力を取得するには、Accept: text/plain ヘッダーを使用します。
レンダリング時に設定コンテキストを上書きする
# POST body merges after config context (overrides on collision)
response = requests.post(
f"{NETBOX}/api/dcim/devices/42/render-config/",
headers=headers,
json={"ntp_servers": ["10.99.99.1"]}, # overrides config context
)
テンプレートを直接レンダリングする(デバイスなし)
# General-purpose rendering — no device/VM in context
response = requests.post(
f"{NETBOX}/api/extras/config-templates/5/render/",
headers=headers,
json={"hostname": "switch01", "vlans": [10, 20, 30]},
)
pynetbox とエラー処理を含む詳細な API の例については、references/api-rendering-patterns.md を参照してください。
注意点
パフォーマンス
- リストエンドポイントでの設定コンテキスト:
- NetBox 4.7+:マージ済みの設定コンテキストは各デバイス/VM 上で事前にレンダリングされ、キャッシュされます。すべての 4.7.x では
?exclude=config_contextは暗黙に無視されます(共有クライアントから引き続き送信されても問題ありません)。4.7.0~4.7.2 では常に読み込まれ、リスト呼び出しの負荷は低く、処理負荷はバックグラウンドの再レンダリングジョブに移っています。4.7.3+ では?omit=config_context(または?fields=/?brief=True)を指定すると、DB のアノテーションとキャッシュ済みカラムの読み込みが再びスキップされます。コンテキストが不要な場合は指定してください。 - NetBox 4.5/4.6:デバイスごとのマージ済み設定コンテキストの計算は負荷が高いため、不要な場合は一括クエリで常に
GET /api/dcim/devices/?omit=config_context(4.5.2+。このバージョンでは?exclude=も同等です)を送信してください。
- NetBox 4.7+:マージ済みの設定コンテキストは各デバイス/VM 上で事前にレンダリングされ、キャッシュされます。すべての 4.7.x では
- テンプレート内の ORM クエリにはガードレールがありません。大規模なテーブルに対する無制限の
.all()は避けてください。
テンプレートの動作
- テンプレートの解決は最初に一致したものだけです — デバイス → ロール → プラットフォームの順です。デバイスに割り当てられるテンプレートは引き続き 1 つです。NetBox 4.6+ では、レンダー設定リクエストの本文に
config_template_idを渡す(または UI のレンダー URL に?config_template_id=<id>を指定する)ことで、割り当てを変更せずにデバイスのコンテキストに対してほかのテンプレートをレンダリングできます。代替テンプレートを CI/ドライランでレンダリングする際に便利です。(Config Template のview権限と、デバイスのrender_config権限が必要です。) - テンプレートのバージョン管理はありません — テンプレートは変更可能です。履歴を確認できるのは NetBox の変更ログのみです。
- レンダリングのデバッグ(NetBox 4.6+) — スクリプト/プラグインでテンプレートを開発する際は、
render_jinja2(..., debug=True)を呼び出して Jinja2 のdebug拡張({% debug %})を有効にし、利用可能なコンテキストを確認できます。 - extends/include には DataSource が必要です — インラインの template_code からほかのテンプレートを参照することはできません。
設定コンテキストに関する注意点
- リストは追加ではなく置き換えられます — よくある注意点です。上記のマージルールを参照してください。
- POST データは設定コンテキストを暗黙に上書きします — 意図的な動作ですが、予期しない値のデバッグ時に混乱を招くことがあります。
- environment_params はテンプレートごとに異なります — 設定によっては、テンプレート間で未定義変数の処理が異なる場合があります。
バージョンに関する注意
NetBox 4.7 (2026-09-02)
- 設定コンテキストはデバイス/VM ごとに事前にレンダリングされ、キャッシュされます。上流の変更時に無効化され、バックグラウンドジョブで再レンダリングされます(その間はオンデマンドでフォールバックします)。すべての 4.7.x では
?exclude=config_contextが暗黙に無視されます。config_contextは 4.7.0~4.7.2 では常に読み込まれますが、4.7.3+ では?omit=config_context/?fields=/?brief=Trueで除外すると、DB のアノテーションが再びスキップされます。DeviceWithConfigContextSerializer/VirtualMachineWithConfigContextSerializerはベースのシリアライザーに統合されました。アップグレード時にrebuild_config_context_cacheが実行されます。 JINJA2_FILTERSはJINJA_FILTERSに名称変更されました(旧名称は 5.0 まで非推奨の警告付きで使用できます)。- プラグインで Jinja フィルターの登録とコンテキスト変数の注入が可能になりました(
jinja_env.py、register_jinja_filters()、get_jinja_context())。優先順位は組み込み → プラグイン → インスタンスのJINJA_FILTERSです。netbox-custom-objects v0.6.1+ はこれを使用してcustom_objects.<type>/'<type>' | custom_objectsを公開します。 - テンプレートから新たにアクセスできるデータ:
device.cooling_method、インターフェースのchannels/channel_id(タイプがchannelのチャネル化されたサブインターフェース)、サービスのport_mappings("tcp/80"形式の文字列のリスト。protocol/portsは非推奨)、device_type.end_of_life。選択型カスタムフィールドは、テンプレートでは引き続きdevice.cf/custom_field_dataを通じて生の値として読み取られます。{value, label}形式になったのは REST/GraphQL の表現のみです。 - プラットフォーム:PostgreSQL 15+、Redis 6.0+、
ltree拡張機能。4.7.3+ を推奨します(4.7.0/4.7.1 ではトークンの平文がジョブ結果に漏洩し、4.7.3 ではブランチを考慮した安全なバックグラウンド書き込みと、設定コンテキストの omit による最適化が追加されました)。
NetBox 4.6(2026-05-05)
- render-config での
config_template_idのオーバーライド(4.6.0);render_jinja2(..., debug=True)(4.6.0);environment_paramsの許可リスト(4.6.1、CVE-2026-29514);組み込みのenvフィルターをJINJA_ENVIRONMENT_PARAMSで制限(4.6.2);SandboxedEnvironmentでレンダリングされる設定テンプレートの自動エスケープを明示的に無効化(4.6.5)。
参考資料
- references/context-variables.md — すべてのレンダリングモードのコンテキスト変数リファレンス
- references/config-context-merging.md — 階層、重み、マージ動作の詳細
- references/api-rendering-patterns.md — pynetbox と requests を使った詳細な API の例