惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Spread Privacy
Spread Privacy
P
Palo Alto Networks Blog
P
Proofpoint News Feed
AI
AI
Help Net Security
Help Net Security
S
Securelist
T
Troy Hunt's Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cisco Blogs
Scott Helme
Scott Helme
Hacker News - Newest:
Hacker News - Newest: "LLM"
Vercel News
Vercel News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
GbyAI
GbyAI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
S
Security Affairs
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
T
Tenable Blog
H
Help Net Security
NISL@THU
NISL@THU
F
Fortinet All Blogs
博客园_首页
G
GRAHAM CLULEY
L
LINUX DO - 最新话题
P
Privacy International News Feed
G
Google Developers Blog
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Archives - TechRepublic
Security Archives - TechRepublic
The Register - Security
The Register - Security
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
T
Tor Project blog
P
Privacy & Cybersecurity Law Blog
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
Forbes - Security
Forbes - Security
S
Secure Thoughts
Simon Willison's Weblog
Simon Willison's Weblog
D
Docker
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
L
Lohrmann on Cybersecurity
T
Tailwind CSS Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Deploy Ping Identity Products on Kubernetes with a Single Operator
DarkEdges · 2026-05-27 · via DEV Community

Running Ping Identity's product suite on Kubernetes typically means wrestling with the ping-devops Helm chart directly, a large umbrella chart with hundreds of values, no shared defaults across products, and no native Kubernetes status model. The pingone-operator wraps that chart in a set of purpose-built custom resources so you declare what you want and the operator figures out the Helm details.

In this post I'll walk through how the operator works, how to install it, and how to get PingFederate (and the rest of the suite) running in a cluster.

The design in one paragraph

The operator introduces six custom resource definitions:

  • PingEnvironment shared configuration: tenant ID, tier (development / staging / production), base domain, and ingress defaults.
  • PingFederate, PingDirectory, PingAccess, PingAuthorize, PingAuthorizePAP, one CR per product, each referencing a PingEnvironment via spec.environmentRef.

Underneath, everything still maps to a single ping-devops Helm release per environment. Products are enabled or disabled in that release based on which product CRs exist. You get independent Kubernetes API objects (separate RBAC, separate status, deploy or remove products without touching shared config) without needing separate Helm releases.

Prerequisites

Requirement Version
Kubernetes 1.26+
kubectl matching cluster
Helm 3.x (CLI, for install only)
Ping Identity DevOps account register here

You'll also need a devops-secret in whatever namespace products will be deployed to:

kubectl create secret generic devops-secret \
  --namespace pingone \
  --from-literal=PING_IDENTITY_ACCEPT_EULA=YES \
  --from-literal=PING_IDENTITY_DEVOPS_USER=<your-devops-user> \
  --from-literal=PING_IDENTITY_DEVOPS_KEY=<your-devops-key>

Enter fullscreen mode Exit fullscreen mode

Installing the operator

Option A: from the OCI Helm chart

helm upgrade --install pingone-operator \
  oci://ghcr.io/darkedges/charts/pingone-operator \
  --version 0.1.0 \
  --namespace pingone-system \
  --create-namespace

Enter fullscreen mode Exit fullscreen mode

Option B: from source (Docker Desktop)

git clone https://github.com/darkedges/pingone-operator
cd pingone-operator
make docker-desktop   # builds image, loads it into Docker Desktop, deploys

Enter fullscreen mode Exit fullscreen mode

Either way, verify the operator is running:

kubectl get pods -n pingone-system
# NAME                                                READY   STATUS    RESTARTS   AGE
# pingone-operator-controller-manager-...             1/1     Running   0          30s

Enter fullscreen mode Exit fullscreen mode

Then install the CRDs if they aren't already:

make install
# or: kubectl apply -f config/crd/bases/

Enter fullscreen mode Exit fullscreen mode

Creating your first environment

A PingEnvironment holds the shared config that all product CRs in the same namespace will inherit.

# env-dev.yaml
apiVersion: pingone.io/v1alpha1
kind: PingEnvironment
metadata:
  name: env-dev
  namespace: pingone
spec:
  tenantId: myorg-dev           # Helm release name: myorg-dev-ping
  tier: development             # development | staging | production
  domain: dev.myorg.example.com # base domain for auto-derived hostnames

  # Shared ingress: all product CRs inherit this unless they override it
  ingress:
    enabled: true
    className: nginx
    annotations:
      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      cert-manager.io/cluster-issuer: "letsencrypt-prod"

Enter fullscreen mode Exit fullscreen mode

kubectl apply -f env-dev.yaml
kubectl get pingenvironments -n pingone
# NAME      PHASE   AGE
# env-dev   Ready   5s

Enter fullscreen mode Exit fullscreen mode

No Helm release is created yet, the environment is a coordination point, not a trigger by itself.

Adding PingFederate

Create a PingFederate CR that references the environment:

# pf-dev.yaml
apiVersion: pingone.io/v1alpha1
kind: PingFederate
metadata:
  name: dev-pf
  namespace: pingone
spec:
  environmentRef: env-dev       # references the PingEnvironment above
  version: "13.0.2-edge"
  replicas: 1

  engineIngress:
    enabled: true
    # hostname auto-derived: pf.dev.myorg.example.com
    tlsSecretRef: pf-tls

  adminIngress:
    enabled: true
    # hostname auto-derived: pf-admin.dev.myorg.example.com
    tlsSecretRef: pf-admin-tls

  config:
    serverProfile:
      url: https://github.com/pingidentity/pingidentity-server-profiles.git
      path: getting-started/pingfederate

Enter fullscreen mode Exit fullscreen mode

kubectl apply -f pf-dev.yaml

Enter fullscreen mode Exit fullscreen mode

The PingFederate reconciler validates the CR and queues the PingEnvironment reconciler. That reconciler discovers all product CRs pointing at env-dev, builds the combined Helm values, and installs or upgrades the myorg-dev-ping release.

Watch it come up:

kubectl get pingfederates -n pingone
# NAME     ENVIRONMENT   PHASE   AGE
# dev-pf   env-dev       Ready   90s

kubectl get pods -n pingone
# NAME                                        READY   STATUS    AGE
# myorg-dev-ping-pingfederate-engine-0        1/1     Running   80s
# myorg-dev-ping-pingfederate-admin-0         1/1     Running   80s

Enter fullscreen mode Exit fullscreen mode

Hostnames are derived automatically

When spec.domain is set on the PingEnvironment, you don't need to spell out every hostname. The operator derives them:

Product Auto-derived hostname
PingFederate engine pf.<domain>
PingFederate admin pf-admin.<domain>
PingDataConsole pd-console.<domain>
PingAccess admin pa-admin.<domain>
PingAccess engine pa.<domain>
PingAuthorize paz.<domain>
PingAuthorizePAP paz-pap.<domain>

Override any of them by setting hostname inside the component's ingress block:

engineIngress:
  enabled: true
  hostname: sso.myorg.example.com   # explicit override
  tlsSecretRef: sso-tls

Enter fullscreen mode Exit fullscreen mode

Adding more products

Each product is its own CR. Add them in any order, the operator reconciles the full set each time any one of them changes.

PingDirectory

apiVersion: pingone.io/v1alpha1
kind: PingDirectory
metadata:
  name: dev-pd
  namespace: pingone
spec:
  environmentRef: env-dev
  replicas: 1
  storageSize: 8Gi
  config:
    serverProfile:
      url: https://github.com/pingidentity/pingidentity-server-profiles.git
      path: baseline/pingdirectory
    userBaseDN: "dc=myorg,dc=com"

Enter fullscreen mode Exit fullscreen mode

PingAuthorize (with a startup dependency on PingDirectory)

apiVersion: pingone.io/v1alpha1
kind: PingAuthorize
metadata:
  name: dev-paz
  namespace: pingone
spec:
  environmentRef: env-dev
  replicas: 1
  ingress:
    enabled: true
    tlsSecretRef: paz-tls
  container:
    waitFor:
      - application: pingDirectory
        service: ldaps
        timeoutSeconds: 300
  config:
    serverProfile:
      url: https://github.com/pingidentity/pingidentity-server-profiles.git
      path: paz-pap-integration/pingauthorize
    serverProfileLayers:
      - name: paz
        url: https://github.com/pingidentity/pingidentity-server-profiles.git
        path: baseline/pingauthorize

Enter fullscreen mode Exit fullscreen mode

PingAuthorizePAP

apiVersion: pingone.io/v1alpha1
kind: PingAuthorizePAP
metadata:
  name: dev-pap
  namespace: pingone
spec:
  environmentRef: env-dev
  ingress:
    enabled: true
    tlsSecretRef: paz-pap-tls
  config:
    serverProfile:
      url: https://github.com/pingidentity/pingidentity-server-profiles.git
      path: paz-pap-integration/pingauthorizepap

Enter fullscreen mode Exit fullscreen mode

PingAccess (waits for PingFederate)

apiVersion: pingone.io/v1alpha1
kind: PingAccess
metadata:
  name: dev-pa
  namespace: pingone
spec:
  environmentRef: env-dev
  version: "8.1.0-edge"
  adminIngress:
    enabled: true
    tlsSecretRef: pa-admin-tls
  engineIngress:
    enabled: true
    tlsSecretRef: pa-tls
  container:
    waitFor:
      - application: pingFederate
        service: https
        timeoutSeconds: 300
  config:
    serverProfile:
      url: https://github.com/pingidentity/pingidentity-server-profiles.git
      path: getting-started/pingaccess

Enter fullscreen mode Exit fullscreen mode

Startup ordering with waitFor

The container.waitFor block controls which services a container waits for before it starts. Under the hood this maps to the WAIT_FOR env var in the ping-devops Docker images.

container:
  waitFor:
    - application: pingDirectory
      service: ldaps
      timeoutSeconds: 300
    - application: pingFederate
      service: https
      timeoutSeconds: 300

Enter fullscreen mode Exit fullscreen mode

Logical application names like pingDirectory, pingFederateAdmin, pingAccessEngine are resolved by the operator to the correct Helm sub-chart service names automatically.

Layered server profiles

The operator supports Ping Identity's layered profile pattern. Use serverProfileLayers to chain profiles:

config:
  serverProfile:
    url: https://github.com/myorg/ping-profiles.git
    path: extensions/pingfederate
    parent: baseline           # chains to the layer named "baseline"

  serverProfileLayers:
    - name: baseline
      url: https://github.com/pingidentity/pingidentity-server-profiles.git
      path: baseline/pingfederate

Enter fullscreen mode Exit fullscreen mode

The operator translates these to the SERVER_PROFILE_* and SERVER_PROFILE_<LAYER>_* env var convention the Docker images expect.

Resource sizing with tier

Set tier once on the PingEnvironment and the operator applies appropriate CPU/memory requests and limits to every product:

Tier PingFederate PingDirectory PingAccess PingAuthorize
development 500m / 512Mi 500m / 1Gi 500m / 512Mi 500m / 1Gi
staging 1 / 1Gi 1 / 2Gi 1 / 1Gi 1 / 2Gi
production 2 / 2Gi 2 / 4Gi 2 / 2Gi 2 / 4Gi

Checking status

Each resource has its own Phase field and standard Kubernetes conditions:

kubectl get pingenvironments,pingfederates,pingdirectories -n pingone
# NAME                               PHASE   AGE
# pingenvironment.pingone.io/env-dev Ready   10m
#
# NAME                               ENVIRONMENT   PHASE   AGE
# pingfederate.pingone.io/dev-pf     env-dev       Ready   8m
# pingdirectory.pingone.io/dev-pd    env-dev       Ready   7m

Enter fullscreen mode Exit fullscreen mode

Drill into conditions with:

kubectl describe pingfederate dev-pf -n pingone

Enter fullscreen mode Exit fullscreen mode

Removing a product

Delete the product CR. The operator detects the deletion, rebuilds Helm values with that product disabled, and upgrades the release in place. The other products keep running.

kubectl delete pingaccess dev-pa -n pingone
# PingAccess pods terminate; PingFederate and PingDirectory are unaffected

Enter fullscreen mode Exit fullscreen mode

Delete the PingEnvironment to tear down the entire Helm release:

kubectl delete pingenvironment env-dev -n pingone
# Finalizer triggers Helm uninstall; all product pods are removed

Enter fullscreen mode Exit fullscreen mode

What's next