Best Practices for the JFrog Crossplane Providers
Plan names, apply order, ownership, tenancy, and GitOps for the JFrog Crossplane providers.
Plan how you structure, name, order, and own JFrog objects before you manage them at scale with the JFrog Crossplane providers.
Structure and Naming
Structure your managed resources as follows:
- Use namespaced Kinds (
*.m.crossplane.io), one namespace per team or domain. Use Kubernetes role-based access control (RBAC) to decide who may manage which JFrog objects. - Always write
providerConfigRefwith bothkindandname.
Choose names carefully:
- For most Kinds,
metadata.nameis the JFrog identifier, and you can't rename it later.- Avoid generic names (
dev,my-group) on a shared JFrog Platform. - A managed resource adopts an existing object of the same name, reconfigures it, and deletes it when the managed resource is deleted.
- Avoid generic names (
- Kubernetes names must be lowercase DNS-1123. For identifiers with uppercase or underscores (
Block_High_CVEs), use a validmetadata.nameand setcrossplane.io/external-namebefore the first apply.
JFrog also applies the following naming rules.
| Object | Naming rule |
|---|---|
| Project keys | 2-32 lowercase alphanumerics or hyphens, starting with a letter |
| Environments | Stored as <projectKey>-<name> (32 characters in total) |
Repositories assigned with projectKey | Must be named <projectKey>-... |
| Xray webhook names | Alphanumeric only |
Apply in Order
You can apply everything at once. The providers retry references and API errors with backoff, so the system converges.
For faster, quieter rollouts, apply in waves (folders or Argo CD sync waves) and wait between them:
kubectl wait --for=condition=Ready -R -f <dir> --timeout=5mApply the waves in this order:
- Identity: users, platform groups, group membership, global roles.
- Projects, environments, project roles, and membership.
- Local and remote repositories, then virtual repositories.
- Permissions, cleanup policies, webhooks, replication.
- Xray policies, then watches, then reports.
Delete in the reverse order. Enforce that order with Usage objects. For more information, see Configure GitHub Actions OIDC and Safe Teardown with Crossplane.
Keep One Owner per Relationship
If two managed resources write the same relationship, they overwrite each other on every poll (flapping). Pick one writer for each relationship.
| Relationship | Possible writers | Recommendation |
|---|---|---|
| Group membership | Artifactory provider's User.groups, Artifactory provider's Group.usersNames, Platform provider's GroupMembers.members | Pick one. With GroupMembers, put a user's groups in spec.initProvider. |
| Group members | Platform provider's Group.members (deprecated, ignored) or GroupMembers | Use GroupMembers. |
| Repository in a project | repository projectKey or project Repository | One per repository |
| Proxy on remote repositories | Artifactory provider's Proxy (attached by Artifactory) or repository proxy | Set proxy explicitly, or omit LateInitialize. |
| Singletons (mail server, trash can, general security, Xray settings, workers count, license, SAML, Crowd, HTTP SSO, reverse proxy, lifecycle) | Any second managed resource of the Kind | Exactly one managed resource per JFrog Platform (per project for Lifecycle) |
Activate Only the Kinds You Use
In Crossplane v2, resource types can be installed as ManagedResourceDefinitions and activated by a ManagedResourceActivationPolicy.
- The default Helm install activates everything.
- If your platform restricts activation, activate what you need, for example
*.artifactory.m.crossplane.io. - An inactive Kind fails with
no matches for kind.
All four providers support SafeStart: controllers start when their CustomResourceDefinition (CRD) is active. The provider-artifactory provider defines more than 430 CRDs, so activating only the Kinds you use reduces API-server load.
Provider-Specific Guidance
Follow these tips for each type of JFrog object.
Local Repositories
- Set
xrayIndex: truewhen Xray should scan the repository. - Set
projectKeyplusprojectEnvironmentsfor project repositories. includesPatternandexcludesPatternare comma-separated strings.- For Docker, use
maxUniqueTags,tagRetention, andblockPushingSchema1.
Remote Repositories
urlis required.- Upstream credentials go in
usernamepluspasswordSecretRef. curated: trueenables JFrog Curation.- Many network settings are late-initialized.
Virtual Repositories
- Every member in
repositoriesmust exist. Until then, JFrog returnsRepository <key> does not exist. - The member order determines resolution.
defaultDeploymentRepoenables deploys through the virtual URL.
Federated Repositories
- Federated repositories need several Artifactory instances reachable on their external URLs, and an Enterprise+ subscription.
- Every
member[]needs a full repository URL, including the local one.
Signed Package Types
- For Alpine, Ansible, Debian, RPM, and Hex, create key pairs first. Name them in
primaryKeypairRefandsecondaryKeypairRef(plain strings). - Package-type availability depends on your Artifactory version. Cargo needs the Custom URL Base.
Xray
- Create policies before watches.
- In
watchResource, setrepoType: remotefor remote repositories, and enablexrayIndexon watched repositories. - Start with notify-only actions before
blockDownloadorfailBuild. CurationPolicyneeds curated remote repositories.- Reports are one-shot.
Access
- Use the Platform provider's
Permission(the Artifactory provider'sPermissionTargetis deprecated) andGroupMembers. - Every principal and repository you name must exist.
- Never manage the built-in admin user from automation.
Multi-Tenancy and GitOps
- Grant teams RBAC on the managed resource groups they need in their namespace, for example
repository.artifactory.m.crossplane.ioandpolicy.xray.m.crossplane.io. Don't grant RBAC on configuration Kinds or singletons. - A namespaced managed resource can reference any
ClusterProviderConfigby name. Restrict this with one of the following options:- Restrict
spec.providerConfigRefwith an admission policy (Kyverno, Gatekeeper, ValidatingAdmissionPolicy). - Give each namespace its own
ProviderConfigwith a least-privilege token.
- Restrict
- Keep the provider installation (Providers, DeploymentRuntimeConfig, provider configurations) in a separate platform application from team manifests.
- Make sure your Argo CD version has health checks for Crossplane resources, so sync waves wait for
Ready.
Compositions and Usages
- Compositions: A
CompositeResourceDefinitionplus a function-pipelineCompositionlet a platform team offer one higher-level object.- For example, a namespaced
TeamWorkspacecan render a Project, environments, a role, repositories named<projectKey>-<type>-local, a Permission, a SecurityPolicy, and a Watch. - Use
matchControllerRef: truein selectors so composed resources reference their siblings. - To debug a Composition, run
crossplane beta trace <kind>/<name> -n <ns>.
- For example, a namespaced
- Usages: A
protection.crossplane.io/v1beta1Usageblocks deleting one resource while another resource uses it.- For example, a Usage can protect a SecurityPolicy that a Watch uses.
- For more information, see Configure GitHub Actions OIDC and Safe Teardown with Crossplane.
Next Steps
- To start from working manifests, see Set Up JFrog Identity and Projects with Crossplane.
- To manage the lifecycle of individual objects, see Manage JFrog Objects with Crossplane.
- To look up the fields of a Kind, see JFrog Crossplane Kinds Reference.
Updated about 1 hour ago
