minimumReleaseAgeの仕組み
RenovateにはminimumReleaseAgeという設定があり、「公開されてからN日未満のバージョンは更新候補として扱わない(ゼロデイ攻撃対策)」という制御ができる。
{
matchManagers: ["npm"],
minimumReleaseAge: "7 days",
}
サプライチェーン攻撃対策として、公開直後の(攻撃者に乗っ取られたアカウントから公開されたかもしれない)バージョンを自動更新で取り込まないようにする、というのが主な用途。
この機能は、依存の「公開日時」(releaseTimestamp)をRenovateが取得できて初めて機能する。取得元は依存の種類ごとに異なるdatasourceというモジュールで、releaseTimestampをサポートしているかどうかは公式ドキュメントのdocs.renovatebot.com/modules/datasource/*で個別に定義されている。
releaseTimestampが取得できない場合の挙動は、minimumReleaseAgeBehaviourというオプションで制御される。既定値は"timestamp-required"。
// lib/util/minimum-release-age.ts(Renovate公式ソース、v43.288.0)
// releaseTimestampが無い場合:
// minimumReleaseAgeBehaviour === 'timestamp-required' なら isPending: true(保留)
つまり既定では、「日時が分からない場合は安全側に倒して保留のまま扱う」という動きになる。これが「7日待てば通る」ではなく「日時が永遠に取れないので更新自体が止まる」という副作用を生む原因になる。
以下、実際にreleaseTimestampが取れない・取れにくいケースを3パターン紹介する。
パターン1: git-tags datasource(GitHub APIを迂回するケース)
GitHub Actions・カスタムのバージョン追跡で、通常はgithub-releasesやgithub-tagsというdatasource(GitHub API経由、公開日時付き)を使う。しかし、対象リポジトリ側がGitHubのIP allow listを有効にしていると、Renovateの認証(GitHub App)でのアクセスが403で弾かれることがある。
Although you appear to have the correct authorization credentials, the
`<organization>` organization has an IP allow list enabled, and your IP
address is not permitted to access this resource.
これはGitHub公式の仕様上、想定された挙動でもある。
"IP allow lists do not restrict access to: Public resources, when accessed anonymously"
— Managing allowed IP addresses for your organization
つまり認証済みアクセスはIP allow listでブロックされるが、匿名アクセスはブロックされない。この回避策として、GitHub APIを使わずgit ls-remoteベースで動作するgit-tagsというdatasourceに切り替えるケースがある。
ただし、このgit-tagsはRenovate公式ソースコードを見ると、そもそもreleaseTimestampというフィールドを設定していない。
// lib/modules/datasource/git-tags/index.ts(Renovate公式ソース、v43.288.0)
const releases = rawRefs
.filter((ref) => ref.type === 'tags')
.map((ref) => ({
version: ref.value,
gitRef: ref.value,
newDigest: ref.hash,
// releaseTimestamp は無い
}));
gitのタグ自体に「いつ作られたか」という情報が乗っていない(gitのプロトコル自体の制約)ため、API経由と違って原理的に取得できない。IP allow listを回避した結果、今度はminimumReleaseAgeが機能しなくなる、という構図になる。
実例として、aquasecurity(trivy-actionの配布元)自身のリポジトリでも同種の問題が報告されている。
回避策とその限界
GitHub App認証ではなく、個人アクセストークン(PAT)をhostRulesで使うことでIP allow listを回避できたという報告がある。
{
"hostRules": [
{
"matchHost": "https://api.github.com/repos/<org>",
"token": "FINE_GRAINED_PAT_WITH_PUBLIC_READ_ONLY"
}
]
}
renovatebot/renovate Discussion #43238
renovatebot/renovate Discussion #17826
これはGitHub App認証とPAT認証でIP allow listの効き方に一貫性が無いという、GitHub側の挙動の揺れに依存した非公式の回避策であり、公式に保証された挙動ではない。また、PATは個人のGitHubアカウントに紐づく認証情報であるため、組織の自動化に組み込む場合はアカウントの運用リスク(退職・異動でトークンが失効する、監査ログの主体が個人になる等)を伴う。
パターン2: 言語ランタイムのバージョン管理datasource
Pythonのバージョンを追跡するpython-versionというdatasourceは、公式ドキュメントの仕様表に明記されている。
Release timestamp support: No
— python-version | Renovate Docs
こちらはパターン1のような「認証がブロックされて代替手段に逃げた」結果ではなく、その言語のバージョン取得API自体が、最初からタイムスタンプを提供していないという、より根本的な制約。回避策が無いdatasource固有の仕様であり、minimumReleaseAgeは機能しない前提で扱う必要がある。
パターン3: Docker Hub以外のコンテナレジストリ
Renovateのdockerdatasourceは、Docker Hubのイメージだけ特別扱いしている。
| レジストリ | 問い合わせ方法 | タイムスタンプ |
|---|---|---|
| Docker Hub | Docker Hub独自API(hub.docker.com/v2/...) |
取れる |
| ECR、GHCRなど | 業界標準API(Docker Registry HTTP API v2) | 取れない(タグ名のみ) |
理由は、Docker Hubは独自のWeb APIで「タグの公開日時」を提供しているのに対し、他のレジストリは標準のDocker Registry HTTP API v2しか実装しておらず、そこにはタグ名しか含まれないため。
さらに厄介なのは、AWSのECR pull-through cache(Docker Hubのイメージをキャッシュ経由でミラーする機能)を使っているケース。中身は本物のDocker Hubのイメージだが、URLがECRのものになるため、Renovateは「ECRのイメージだ」と誤認してタイムスタンプを取得しに行かず、結果としてminimumReleaseAgeが機能しなくなる。
Renovate の minimum-release-age を ECR pull-through cache で使う - Classmethod
この記事で紹介されている対策がregistryAliases。「このURLは実体がDocker Hubだと思って問い合わせて」とRenovateに教えることで、メタデータ取得先とファイル書き換え先を分離できる。
{
"registryAliases": {
"123456789012.dkr.ecr.us-east-1.amazonaws.com/dockerhub": "docker.io"
}
}
ただし、これが効くのは「元々Docker Hubのイメージをミラーしているケース」だけで、GHCRなど最初からDocker Hub以外にしか存在しないイメージには適用できない。
まとめ
| ケース | 原因 | 回避策 |
|---|---|---|
| git-tags datasource(GitHub API迂回) | gitプロトコル自体にタイムスタンプが無い | PATでIP allow listを回避(非公式・運用リスクあり) |
| python-version datasource | APIがタイムスタンプ非対応 | なし |
| Docker Hub以外のレジストリ直接参照 | API仕様の違い | なし |
| ECR pull-through cache経由のDocker Hubイメージ | Renovateがレジストリを誤認 |
registryAliasesで解決可 |
minimumReleaseAgeを設定する際は、対象の依存がどのdatasourceを経由しているか、そのdatasourceがreleaseTimestampをサポートしているかを、docs.renovatebot.com/modules/datasource/*の仕様表で個別に確認する必要がある。サポートしていない場合、既定動作(minimumReleaseAgeBehaviour: "timestamp-required")では、待機期間を待つのではなく更新自体が保留され続ける点に注意が必要。
参考リンク
- minimum-release-age | Renovate Docs
- Renovate公式ソース: git-tags datasource (v43.288.0)
- Renovate公式ソース: minimum-release-age判定ロジック (v43.288.0)
- python-version datasource | Renovate Docs
- aquasecurity/trivy Discussion #10441
- GitHub Docs: Managing allowed IP addresses for your organization
- renovatebot/renovate Discussion #43238
- renovatebot/renovate Discussion #17826
- Renovate の minimum-release-age を ECR pull-through cache で使う - Classmethod