Set Up JFrog Identity and Projects with Crossplane
Create users, a group, group membership, a global role, and a project with the JFrog Crossplane providers.
Use these Crossplane recipes to set up identity and projects in the JFrog Platform. Each recipe is a set of manifests that combines the JFrog Crossplane providers.
- Recipe 1 creates a user, a platform group, the group membership, and a global role.
- Recipe 2 creates a project, an environment, a project role, and a project membership for the group.
Prerequisites
- The providers are installed, and ClusterProviderConfigs named
jfrogexist. For more information, see Configure Credentials for the JFrog Crossplane Providers. - The recipes use the namespace
team-paymentsand the project keypayments. These values differ from theteam-anamespace used on other pages.
Note
The manifests on this page omit
providerConfigReffor brevity. Every managed resource also needsproviderConfigRef: {kind: ClusterProviderConfig, name: jfrog}underspec. Add it to each managed resource before you apply, or name your configurationsdefault.
Recipe 1: Users, Group, Membership, and Global Role
Step 1: Create the Recipe 1 Manifests
Save the following manifests to a directory:
apiVersion: v1
kind: Secret
metadata: {name: user-password, namespace: team-payments}
stringData: {password: '<initial-password>'}
---
apiVersion: user.artifactory.m.crossplane.io/v1alpha1
kind: User
metadata: {name: alice, namespace: team-payments}
spec:
initProvider:
groups: [readers] # initial only: GroupMembers owns membership
forProvider:
email: [email protected]
profileUpdatable: true
passwordSecretRef: {name: user-password, key: password}
---
apiVersion: access.platform.m.crossplane.io/v1alpha1
kind: Group
metadata:
name: payments-developers
namespace: team-payments
labels: {app.example.com/group: payments-developers}
spec:
forProvider: {description: Payments developers, adminPrivileges: false, autoJoin: false}
---
apiVersion: access.platform.m.crossplane.io/v1alpha1
kind: GroupMembers
metadata: {name: payments-developers, namespace: team-payments}
spec:
forProvider:
members: [alice] # authoritative list
nameSelector: {matchLabels: {app.example.com/group: payments-developers}}
---
apiVersion: access.platform.m.crossplane.io/v1alpha1
kind: GlobalRole
metadata: {name: payments-auditor, namespace: team-payments}
spec:
forProvider:
type: CUSTOM_GLOBAL
environments: [DEV, PROD]
actions: [READ_REPOSITORY, READ_BUILD]Replace <initial-password> with the initial password for the user.
About these manifests:
- The
Usersetsgroupsunderspec.initProvider, so the value is sent only at creation. GroupMembersowns the group membership. If two managed resources write the same membership, they overwrite each other on every poll.GroupMemberssets the group withnameSelector, which selects the platformGroupby its label.- The
GroupMembersnamefield stays a spec field so that it can usenameRefornameSelector. - The
memberslist is authoritative. It replaces the whole membership list on update.
Step 2: Apply the Recipe 1 Manifests
Run the following command:
kubectl apply -R -f <dir>/To add a user later, apply the new User and append it to members. GroupMembers retries until the user exists.
Recipe 2: Project, Environment, Role, and Membership
Step 1: Create the Recipe 2 Manifests
Save the following manifests to a directory:
apiVersion: project.project.m.crossplane.io/v1alpha1
kind: Project
metadata:
name: payments # project key
namespace: team-payments
labels: {app.example.com/project: payments}
spec:
forProvider:
displayName: Payments
maxStorageInGibibytes: 10
adminPrivileges: [{manageMembers: true, manageResources: true, indexResources: true}]
---
apiVersion: project.project.m.crossplane.io/v1alpha1
kind: Environment
metadata: {name: staging, namespace: team-payments} # stored as payments-staging
spec:
forProvider:
projectKeySelector: {matchLabels: {app.example.com/project: payments}}
---
apiVersion: access.project.m.crossplane.io/v1alpha1
kind: Role
metadata: {name: payments-releaser, namespace: team-payments}
spec:
forProvider:
type: CUSTOM
environments: [DEV, PROD]
actions: [READ_REPOSITORY, ANNOTATE_REPOSITORY, CREATE_RELEASE_BUNDLE, READ_RELEASE_BUNDLE]
projectKeySelector: {matchLabels: {app.example.com/project: payments}}
---
apiVersion: access.project.m.crossplane.io/v1alpha1
kind: Group # adds the existing platform group to the project
metadata: {name: payments-developers, namespace: team-payments}
spec:
forProvider:
roles: [Developer]
projectKeySelector: {matchLabels: {app.example.com/project: payments}}About these manifests:
- The
Projectname is the project key. - The
Environment,Role, and projectGroupselect the project by its label withprojectKeySelector. - Project
GroupandUsernames must match existing principals. The projectGroupin this recipe adds the platform grouppayments-developersfrom Recipe 1. - Built-in project roles are
Developer,Contributor,Viewer,Release Manager,Security Manager, andProject Admin.
Step 2: Apply the Recipe 2 Manifests
Run the following command:
kubectl apply -R -f <dir>/Check the Result
List every managed resource:
kubectl get managed -ATo check one Kind, run the following commands. Use the fully-qualified Kind name, for example groupmembers.access.platform.m.crossplane.io.
kubectl get <fq-kind> -n team-payments
kubectl describe <fq-kind>/<name> -n team-payments- The first command shows the
SYNCED,READY, andEXTERNAL-NAMEcolumns. - The second command shows conditions and events.
Next Steps
- Create repositories, a permission, and Xray policies for the project. For more information, see Create Repositories and Xray Policies with Crossplane.
- Learn how references, selectors, and management policies work. For more information, see Manage JFrog Objects with Crossplane.
- Look up the fields of each Kind. For more information, see JFrog Crossplane Kinds Reference.
Updated about 1 hour ago
