Manage JFrog Objects with Crossplane
Create, update, adopt, pause, and delete JFrog objects with the JFrog Crossplane providers.
Manage the lifecycle of JFrog objects through their managed resources. This page covers everyday commands, management policies, references, Secret inputs, updates, deletion, and adoption of existing objects.
Prerequisites
- The providers are installed, configured, and verified. For more information, see Verify the JFrog Crossplane Providers.
- You know how a managed resource is built. For more information, see How the JFrog Crossplane Providers Work.
Everyday Commands
Use the following commands to inspect and control managed resources:
kubectl get providers # INSTALLED / HEALTHY
kubectl -n crossplane-system get pods
kubectl get managed -A # every managed resource; also: kubectl get artifactory|xray|project|platform -A
kubectl get <fq-kind> -n team-a # SYNCED, READY, EXTERNAL-NAME
kubectl describe <fq-kind>/<name> -n team-a # conditions and events
kubectl explain <fq-kind>.spec.forProvider --recursive # every field of a Kind
kubectl annotate <fq-kind>/<name> -n team-a crossplane.io/paused=true # pause (remove to resume)Replace the following:
<fq-kind>: The fully-qualified Kind name, for examplelocalnpmrepositories.repository.artifactory.m.crossplane.io.<name>: The name of the managed resource.
Control What Crossplane Can Do
spec.managementPolicies controls what Crossplane may do with the JFrog object. The following combinations are common.
| Policies | Behavior |
|---|---|
["*"] (default) | Full control |
["Observe"] | Read-only: report the existing object in status.atProvider, never change it |
["Observe","Create","Update","LateInitialize"] | Manage but never delete (keeps the JFrog object when the managed resource is deleted) |
["Observe","Create","Update","Delete"] | Full control without late initialization |
["Observe","LateInitialize"] | Import: copy the live configuration into spec.forProvider |
["Observe","Update"] | Adopt and enforce an existing object. Never create or delete. |
["Observe","Create"] | Create once, never touch again |
[] | Paused |
The following sets are also supported:
["Observe","Create","Update"]["Observe","Create","Delete","LateInitialize"]["Observe","Create","LateInitialize"]["Observe","Create","Delete"]["Observe","Delete"]["Observe","Update","LateInitialize"]
Crossplane rejects any other combination with the following message: `spec.managementPolicies` is set to a value(...) which is not supported.
Reference Other Managed Resources
Some fields can take their value from another managed resource's external name instead of a literal value:
<field>Ref: {name: <mr-name>}or<field>Refs: [{name: a}, {name: b}].<field>Selector: {matchLabels: {...}}. AddmatchControllerRef: trueinside Compositions.policy.resolve: Alwaysresolves the reference again on every reconcile. The default isIfNotPresent.policy.resolution: Optionaltolerates a missing target.
The target must exist and have its external name set. It doesn't need to be Ready. Until then, the managed resource reports cannot resolve references.
References exist only where a provider defines them, and never across providers. For example, an Artifactory repository's projectKey takes the literal project key.
The following references are available.
| Provider | References |
|---|---|
| Artifactory | Replication repoKeyRef, webhook criteria.repoKeysRefs, and permission-target repositoriesRefs (to LocalGenericRepository). Group.usersNamesRefs (to User) |
| Xray | Watch.assignedPolicy[].nameRef (to SecurityPolicy) |
| Project | projectKeyRef on Environment, Group, Role, User, and Repository. ShareRepository.targetProjectKeyRef |
| Platform | GroupMembers.nameRef (to Group), OIDCIdentityMapping.providerNameRef, Lifecycle.promoteStagesRefs |
Everything else takes literal values. Fields that merely end in Ref (repoLayoutRef, primaryKeypairRef, secondaryKeypairRef) are plain names, not references.
The reference entry for each Kind lists its references. For more information, see JFrog Crossplane Kinds Reference.
Pass Secret Values
Every sensitive field is a <field>SecretRef: {name, key} to a Secret in the managed resource's namespace. Examples:
User.passwordSecretRef- Remote repository
passwordSecretRef - Webhook
handler[].secretSecretRef - LDAP
managerPasswordSecretRef
The exception is custom webhook handler[].secretsSecretRef. It references a whole Secret by name only.
The following rules apply:
- The provider never writes values to status.
Certificatecontent and theLicensekey are Secret references too. The providers don't support local file paths.- Produce the Secrets with External Secrets, Sealed Secrets, SOPS, or Vault.
- The provider sends rotated values on the next reconcile, or immediately after a
reconcile/kickannotation. - Write-only fields are never read back, so the provider doesn't detect their changes.
- An example is remote repository
passwordWoSecretRef, which conflicts withpasswordSecretRef. - Bump the companion version field (
passwordWoVersion) whenever the Secret changes.
- An example is remote repository
Update JFrog Objects
Follow these rules when you update JFrog objects:
- Know the immutable fields before you create an object. The reference entry for each Kind lists them.
- The provider never changes an immutable field in place. It refuses instead of recreating the object, with one of these messages:
diff contains fields that require resource replacement: <fields>refuse to update the external resource because the following update requires replacing it
- When you see one, revert the change, or delete and recreate the object.
- To change an immutable field, create a new managed resource, migrate, then delete the old one.
- The provider never changes an immutable field in place. It refuses instead of recreating the object, with one of these messages:
- Some Kinds can't be updated. Xray reports and project repository assignment Kinds can't be updated. Delete and recreate them. Xray
IgnoreRuleis fully immutable. - Authoritative lists replace the whole list on update. Manage each relationship from one place. These lists are:
- Artifactory provider's
User.groups - Platform provider's
GroupMembers.members - Virtual repository
repositories - Xray provider's
Watch.watchResource
- Artifactory provider's
- Server-normalized values cause endless updates when your spec differs from what JFrog stores. Write server-canonical values, for example sorted webhook
eventTypesand comma-separatedincludesPatternstrings. The reference lists the known cases. - GitOps differences from late initialization: If GitOps tools report differences caused by late initialization, use
managementPolicies: ["Observe","Create","Update","Delete"], Argo CDignoreDifferences, or server-side apply.
Delete JFrog Objects
Deleting a managed resource removes the JFrog object, unless managementPolicies omits Delete. For legacy managed resources, use deletionPolicy: Orphan.
Deletion works as follows:
- The finalizer stays until JFrog confirms the deletion.
- Some upstream deletes are no-ops (platform
Lifecycle). - Deleting a singleton resets it to defaults.
Warning
Deleting a managed resource deletes the JFrog object, including repository content.
Follow these rules to delete safely:
- Protect production repositories, projects, and singletons with
managementPolicies: ["Observe","Create","Update","LateInitialize"]. - GitOps pruning deletes JFrog objects when files are removed. Enable pruning deliberately, or mark critical objects with the Argo CD annotation
argocd.argoproj.io/sync-options: Prune=false. - Project deletion removes everything assigned to the project and takes minutes.
- Before you manage SAML, Crowd, or HTTP SSO settings, keep an administrator access token that doesn't depend on SSO. Test these settings on a non-production JFrog Platform first.
Adopt Existing JFrog Objects
To bring an existing JFrog object under Crossplane management:
- Find the identifier: the repository key, user, group, policy or watch name, project key, or the server ID for server-assigned Kinds (for example
GET /xray/api/v1/curation/policies). - Write the managed resource with
metadata.name(or the external-name annotation) set to the identifier, andmanagementPolicies: ["Observe"]. - Read
status.atProvider. Copy the settings you want to own intospec.forProvider, or use["Observe","LateInitialize"]to have them copied. - Switch to full management.
Warning
Applying with full policies immediately overwrites the live object with your spec. Singletons are adopted automatically. Never adopt one object from two managed resources.
Next Steps
- To plan names, ordering, and ownership, see Best Practices for the JFrog Crossplane Providers.
- To protect objects and tear them down in order, see Configure GitHub Actions OIDC and Safe Teardown with Crossplane.
- If a managed resource doesn't become
SyncedorReady, see Troubleshoot the JFrog Crossplane Providers.
Updated about 1 hour ago
