Files

10 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
13-osint_package_registries_container_iac 03 execute 1
pkg/recon/sources/dockerhub.go
pkg/recon/sources/dockerhub_test.go
pkg/recon/sources/kubernetes.go
pkg/recon/sources/kubernetes_test.go
pkg/recon/sources/terraform.go
pkg/recon/sources/terraform_test.go
pkg/recon/sources/helm.go
pkg/recon/sources/helm_test.go
true
RECON-INFRA-01
RECON-INFRA-02
RECON-INFRA-03
RECON-INFRA-04
truths artifacts key_links
DockerHubSource searches Docker Hub for images matching provider keywords and emits findings
KubernetesSource searches for publicly exposed Kubernetes configs via search/dorking and emits findings
TerraformSource searches Terraform Registry for modules matching provider keywords and emits findings
HelmSource searches Artifact Hub for Helm charts matching provider keywords and emits findings
All four sources handle context cancellation, empty registries, and HTTP errors gracefully
path provides contains
pkg/recon/sources/dockerhub.go DockerHubSource implementing recon.ReconSource func (s *DockerHubSource) Sweep
path provides contains
pkg/recon/sources/kubernetes.go KubernetesSource implementing recon.ReconSource func (s *KubernetesSource) Sweep
path provides contains
pkg/recon/sources/terraform.go TerraformSource implementing recon.ReconSource func (s *TerraformSource) Sweep
path provides contains
pkg/recon/sources/helm.go HelmSource implementing recon.ReconSource func (s *HelmSource) Sweep
from to via pattern
pkg/recon/sources/dockerhub.go pkg/recon/source.go implements ReconSource interface var _ recon.ReconSource
from to via pattern
pkg/recon/sources/terraform.go pkg/recon/source.go implements ReconSource interface var _ recon.ReconSource
Implement four container and infrastructure-as-code ReconSource modules: Docker Hub, Kubernetes, Terraform Registry, and Helm (via Artifact Hub).

Purpose: Enables KeyHunter to scan container images, Kubernetes configs, Terraform modules, and Helm charts for leaked API keys embedded in infrastructure definitions. Output: 4 source files + 4 test files in pkg/recon/sources/

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @pkg/recon/source.go @pkg/recon/sources/httpclient.go @pkg/recon/sources/queries.go @pkg/recon/sources/replit.go (pattern reference) @pkg/recon/sources/shodan.go (pattern reference — search API source) @pkg/recon/sources/replit_test.go (test pattern reference) From pkg/recon/source.go: ```go type ReconSource interface { Name() string RateLimit() rate.Limit Burst() int RespectsRobots() bool Enabled(cfg Config) bool Sweep(ctx context.Context, query string, out chan<- Finding) error } ```

From pkg/recon/sources/httpclient.go:

func NewClient() *Client
func (c *Client) Do(ctx context.Context, req *http.Request) (*http.Response, error)

From pkg/recon/sources/queries.go:

func BuildQueries(reg *providers.Registry, source string) []string
Task 1: Implement DockerHubSource and KubernetesSource pkg/recon/sources/dockerhub.go, pkg/recon/sources/dockerhub_test.go, pkg/recon/sources/kubernetes.go, pkg/recon/sources/kubernetes_test.go **DockerHubSource** (dockerhub.go): - Struct: `DockerHubSource` with `BaseURL`, `Registry`, `Limiters`, `Client` - Compile-time assertion: `var _ recon.ReconSource = (*DockerHubSource)(nil)` - Name() returns "dockerhub" - RateLimit() returns rate.Every(2 * time.Second) — Docker Hub rate limits unauthenticated at ~100 pulls/6h, search is more lenient - Burst() returns 2 - RespectsRobots() returns false (JSON API) - Enabled() always true (Docker Hub search is unauthenticated) - BaseURL defaults to "https://hub.docker.com" - Sweep() logic: 1. BuildQueries(s.Registry, "dockerhub") 2. For each keyword, GET `{BaseURL}/v2/search/repositories/?query={keyword}&page_size=20` 3. Parse JSON: `{"results": [{"repo_name": "...", "description": "...", "is_official": false}]}` 4. Define response structs: `dockerHubSearchResponse`, `dockerHubRepo` 5. Emit Finding per result: Source="https://hub.docker.com/r/{repo_name}", SourceType="recon:dockerhub" 6. Description in finding can hint at build-arg or env-var exposure

KubernetesSource (kubernetes.go):

  • Struct: KubernetesSource with BaseURL, Registry, Limiters, Client
  • Compile-time assertion: var _ recon.ReconSource = (*KubernetesSource)(nil)
  • Name() returns "k8s"
  • RateLimit() returns rate.Every(3 * time.Second)
  • Burst() returns 1
  • RespectsRobots() returns true (searches public web for exposed K8s dashboards/configs)
  • Enabled() always true
  • BaseURL defaults to "https://search.censys.io" — uses Censys-style search for exposed K8s dashboards
  • ALTERNATIVE simpler approach: Search GitHub for exposed Kubernetes manifests containing secrets. Use BaseURL "https://api.github.com" and search for kind: Secret or apiVersion: v1 kind: ConfigMap with provider keywords. BUT this duplicates GitHubSource.
  • BEST approach: Use a dedicated search via pkg.go.dev-style HTML scraping but for Kubernetes YAML files on public artifact hubs. Actually, the simplest approach that aligns with RECON-INFRA-02 ("discovers publicly exposed Kubernetes dashboards and scans publicly readable Secret/ConfigMap objects"): Use Shodan/Censys-style dork queries. But those sources already exist.
  • FINAL approach: KubernetesSource searches Artifact Hub (artifacthub.io) for Kubernetes manifests/operators that may embed secrets. ArtifactHub has a JSON API. GET {BaseURL}/api/v1/packages/search?ts_query_web={keyword}&kind=0&limit=20 (kind=0 = Helm charts, but also covers operators) Actually, use kind=6 for "Kube Operator" or leave blank for all kinds. BaseURL defaults to "https://artifacthub.io" Parse JSON: {"packages": [{"name": "...", "normalized_name": "...", "repository": {"name": "...", "url": "..."}}]} Emit Finding: Source="https://artifacthub.io/packages/{repository.kind}/{repository.name}/{package.name}", SourceType="recon:k8s"

Tests — httptest pattern:

  • dockerhub_test.go: httptest serving canned Docker Hub search JSON. Verify findings have correct SourceType and Source URL format.
  • kubernetes_test.go: httptest serving canned Artifact Hub search JSON. Standard test categories. cd /home/salva/Documents/apikey && go test ./pkg/recon/sources/ -run "TestDockerHub|TestKubernetes" -v -count=1 DockerHubSource and KubernetesSource pass all tests: Docker Hub search returns repo findings, K8s source finds Artifact Hub packages
Task 2: Implement TerraformSource and HelmSource pkg/recon/sources/terraform.go, pkg/recon/sources/terraform_test.go, pkg/recon/sources/helm.go, pkg/recon/sources/helm_test.go **TerraformSource** (terraform.go): - Struct: `TerraformSource` with `BaseURL`, `Registry`, `Limiters`, `Client` - Compile-time assertion: `var _ recon.ReconSource = (*TerraformSource)(nil)` - Name() returns "terraform" - RateLimit() returns rate.Every(2 * time.Second) - Burst() returns 2 - RespectsRobots() returns false (JSON API) - Enabled() always true - BaseURL defaults to "https://registry.terraform.io" - Sweep() logic: 1. BuildQueries(s.Registry, "terraform") 2. For each keyword, GET `{BaseURL}/v1/modules?q={keyword}&limit=20` 3. Parse JSON: `{"modules": [{"id": "namespace/name/provider", "namespace": "...", "name": "...", "provider": "...", "description": "..."}]}` 4. Define response structs: `terraformSearchResponse`, `terraformModule` 5. Emit Finding per module: Source="https://registry.terraform.io/modules/{namespace}/{name}/{provider}", SourceType="recon:terraform"

HelmSource (helm.go):

  • Struct: HelmSource with BaseURL, Registry, Limiters, Client
  • Compile-time assertion: var _ recon.ReconSource = (*HelmSource)(nil)
  • Name() returns "helm"
  • RateLimit() returns rate.Every(2 * time.Second)
  • Burst() returns 2
  • RespectsRobots() returns false (JSON API)
  • Enabled() always true
  • BaseURL defaults to "https://artifacthub.io"
  • Sweep() logic:
    1. BuildQueries(s.Registry, "helm")
    2. For each keyword, GET {BaseURL}/api/v1/packages/search?ts_query_web={keyword}&kind=0&limit=20 (kind=0 = Helm charts)
    3. Parse JSON: {"packages": [{"package_id": "...", "name": "...", "normalized_name": "...", "repository": {"name": "...", "kind": 0}}]}
    4. Define response structs: artifactHubSearchResponse, artifactHubPackage, artifactHubRepo
    5. Emit Finding per package: Source="https://artifacthub.io/packages/helm/{repo.name}/{package.name}", SourceType="recon:helm"
    6. Note: HelmSource and KubernetesSource both use Artifact Hub but with different kind parameters and different SourceType tags. Keep them separate — different concerns.

Tests — httptest pattern:

  • terraform_test.go: httptest serving canned Terraform registry JSON. Verify module URL construction from namespace/name/provider.
  • helm_test.go: httptest serving canned Artifact Hub JSON for Helm charts. Standard test categories. cd /home/salva/Documents/apikey && go test ./pkg/recon/sources/ -run "TestTerraform|TestHelm" -v -count=1 TerraformSource and HelmSource pass all tests. Terraform constructs correct module URLs. Helm extracts Artifact Hub packages correctly.
All 8 new files compile and pass tests: ```bash go test ./pkg/recon/sources/ -run "TestDockerHub|TestKubernetes|TestTerraform|TestHelm" -v -count=1 go vet ./pkg/recon/sources/ ```

<success_criteria>

  • 4 new source files implement recon.ReconSource interface
  • 4 test files use httptest with canned fixtures
  • All tests pass
  • No compilation errors across the package </success_criteria>
After completion, create `.planning/phases/13-osint_package_registries_container_iac/13-03-SUMMARY.md`