|
1 | | -# function-azresourcegraph |
2 | | -[](https://github.com/upbound/function-azresourcegraph/actions/workflows/ci.yml) |
| 1 | +# function-msgraph |
3 | 2 |
|
4 | | -A function to query [Azure Resource Graph][azresourcegraph] |
| 3 | +A Crossplane composition function for querying the Microsoft Graph API. |
5 | 4 |
|
6 | | -## Usage |
| 5 | +## Overview |
7 | 6 |
|
8 | | -See the [examples][examples] for a variety of practical and testable use cases demonstrating this Function. |
| 7 | +The `function-msgraph` provides read-only access to Microsoft Graph API endpoints, allowing Crossplane compositions to: |
9 | 8 |
|
10 | | -Example pipeline step: |
| 9 | +1. Validate Azure AD User Existence |
| 10 | +2. Get Group Membership |
| 11 | +3. Get Group Object IDs |
| 12 | +4. Get Service Principal Details |
11 | 13 |
|
12 | | -```yaml |
13 | | - pipeline: |
14 | | - - step: query-azresourcegraph |
15 | | - functionRef: |
16 | | - name: function-azresourcegraph |
17 | | - input: |
18 | | - apiVersion: azresourcegraph.fn.crossplane.io/v1alpha1 |
19 | | - kind: Input |
20 | | - query: "Resources | project name, location, type, id| where type =~ 'Microsoft.Compute/virtualMachines' | order by name desc" |
21 | | - target: "status.azResourceGraphQueryResult" |
22 | | - credentials: |
23 | | - - name: azure-creds |
24 | | - source: Secret |
25 | | - secretRef: |
26 | | - namespace: upbound-system |
27 | | - name: azure-account-creds |
28 | | -``` |
| 14 | +The function supports throttling mitigation with the `skipQueryWhenTargetHasData` flag to avoid unnecessary API calls. |
29 | 15 |
|
30 | | -The Azure Credentials Secret structure is fully compatible with the standard |
31 | | -[Azure Official Provider][azop] |
| 16 | +## Usage |
32 | 17 |
|
33 | | -Example XR status after e2e query: |
| 18 | +Add the function to your Crossplane installation: |
34 | 19 |
|
35 | 20 | ```yaml |
36 | | -apiVersion: example.crossplane.io/v1 |
37 | | -kind: XR |
| 21 | +apiVersion: pkg.crossplane.io/v1beta1 |
| 22 | +kind: Function |
38 | 23 | metadata: |
39 | | -... |
40 | | -status: |
41 | | - azResourceGraphQueryResult: |
42 | | - - id: /subscriptions/f403a412-959c-4214-8c4d-ad5598f149cc/resourceGroups/us-vm-zxqnj-s2jdb/providers/Microsoft.Compute/virtualMachines/us-vm-zxqnj-2h59v |
43 | | - location: centralus |
44 | | - name: us-vm-zxqnj-2h59v |
45 | | - type: microsoft.compute/virtualmachines |
46 | | - - id: /subscriptions/f403a412-959c-4214-8c4d-ad5598f149cc/resourceGroups/us-vm-lzbpt-tdv2h/providers/Microsoft.Compute/virtualMachines/us-vm-lzbpt-fgcds |
47 | | - location: centralus |
48 | | - name: us-vm-lzbpt-fgcds |
49 | | - type: microsoft.compute/virtualmachines |
| 24 | + name: function-msgraph |
| 25 | +spec: |
| 26 | + package: xpkg.upbound.io/upbound/function-msgraph:v0.1.0 |
50 | 27 | ``` |
51 | 28 |
|
52 | | -### QueryRef |
53 | | -
|
54 | | -Rather than specifying a direct query string as shown in the example above, |
55 | | -the function allows referencing a query from any arbitrary field within the Context or Status. |
| 29 | +### Azure Credentials |
56 | 30 |
|
57 | | -#### Context Query Reference |
| 31 | +Create an Azure service principal with appropriate permissions to access Microsoft Graph API: |
58 | 32 |
|
59 | | -* Simple context field reference |
60 | 33 | ```yaml |
61 | | - queryRef: "context.azResourceGraphQuery" |
| 34 | +apiVersion: v1 |
| 35 | +kind: Secret |
| 36 | +metadata: |
| 37 | + name: azure-account-creds |
| 38 | + namespace: crossplane-system |
| 39 | +type: Opaque |
| 40 | +stringData: |
| 41 | + credentials: | |
| 42 | + { |
| 43 | + "clientId": "your-client-id", |
| 44 | + "clientSecret": "your-client-secret", |
| 45 | + "subscriptionId": "your-subscription-id", |
| 46 | + "tenantId": "your-tenant-id" |
| 47 | + } |
62 | 48 | ``` |
63 | 49 |
|
64 | | -* Get data from Environment |
65 | | -```yaml |
66 | | - queryRef: "context.[apiextensions.crossplane.io/environment].azResourceGraphQuery" |
67 | | -``` |
| 50 | +The service principal needs the following Microsoft Graph API permissions: |
| 51 | +- User.Read.All (for user validation) |
| 52 | +- Group.Read.All (for group operations) |
| 53 | +- Application.Read.All (for service principal details) |
68 | 54 |
|
69 | | -#### XR Status Query Reference |
| 55 | +## Examples |
70 | 56 |
|
71 | | -* Simple XR Status field reference |
72 | | -```yaml |
73 | | - queryRef: "status.azResourceGraphQuery" |
74 | | -``` |
| 57 | +### Validate Azure AD Users |
75 | 58 |
|
76 | | -* Get data from nested field in XR status. Use brackets if key contains dots. |
77 | 59 | ```yaml |
78 | | - queryRef: "status.[fancy.key.with.dots].azResourceGraphQuery" |
| 60 | +apiVersion: example.crossplane.io/v1 |
| 61 | +kind: Composition |
| 62 | +metadata: |
| 63 | + name: user-validation-example |
| 64 | +spec: |
| 65 | + compositeTypeRef: |
| 66 | + apiVersion: example.crossplane.io/v1 |
| 67 | + kind: XR |
| 68 | + pipeline: |
| 69 | + - step: validate-user |
| 70 | + functionRef: |
| 71 | + name: function-msgraph |
| 72 | + input: |
| 73 | + apiVersion: msgraph.fn.crossplane.io/v1alpha1 |
| 74 | + kind: Input |
| 75 | + queryType: UserValidation |
| 76 | + users: |
| 77 | + |
| 78 | + |
| 79 | + target: "status.validatedUsers" |
| 80 | + skipQueryWhenTargetHasData: true |
| 81 | + credentials: |
| 82 | + - name: azure-creds |
| 83 | + source: Secret |
| 84 | + secretRef: |
| 85 | + namespace: crossplane-system |
| 86 | + name: azure-account-creds |
79 | 87 | ``` |
80 | 88 |
|
81 | | -### Targets |
82 | | -
|
83 | | -Function supports publishing Query Results to different locations. |
| 89 | +### Get Group Membership |
84 | 90 |
|
85 | | -#### Context Target |
86 | | -
|
87 | | -* Simple Context field target |
88 | 91 | ```yaml |
89 | | - target: "context.azResourceGraphQueryResult" |
90 | | -``` |
91 | | -
|
92 | | -* Put results into Environment key |
93 | | -```yaml |
94 | | - target: "context.[apiextensions.crossplane.io/environment].azResourceGraphQuery" |
| 92 | +apiVersion: example.crossplane.io/v1 |
| 93 | +kind: Composition |
| 94 | +metadata: |
| 95 | + name: group-membership-example |
| 96 | +spec: |
| 97 | + compositeTypeRef: |
| 98 | + apiVersion: example.crossplane.io/v1 |
| 99 | + kind: XR |
| 100 | + pipeline: |
| 101 | + - step: get-group-members |
| 102 | + functionRef: |
| 103 | + name: function-msgraph |
| 104 | + input: |
| 105 | + apiVersion: msgraph.fn.crossplane.io/v1alpha1 |
| 106 | + kind: Input |
| 107 | + queryType: GroupMembership |
| 108 | + group: "Developers" |
| 109 | + # The function will automatically select standard fields: |
| 110 | + # - id, displayName, mail, userPrincipalName, appId, description |
| 111 | + target: "status.groupMembers" |
| 112 | + skipQueryWhenTargetHasData: true |
| 113 | + credentials: |
| 114 | + - name: azure-creds |
| 115 | + source: Secret |
| 116 | + secretRef: |
| 117 | + namespace: crossplane-system |
| 118 | + name: azure-account-creds |
95 | 119 | ``` |
96 | 120 |
|
97 | | -#### XR Status Target |
| 121 | +### Get Group Object IDs |
98 | 122 |
|
99 | | -* Simple XR status field target |
100 | 123 | ```yaml |
101 | | - target: "status.azResourceGraphQueryResult" |
102 | | -``` |
103 | | -
|
104 | | -* Put query results to nested field under XR status. Use brackets if key contains dots |
105 | | -```yaml |
106 | | - target: "status.[fancy.key.with.dots].azResourceGraphQueryResult" |
| 124 | +apiVersion: example.crossplane.io/v1 |
| 125 | +kind: Composition |
| 126 | +metadata: |
| 127 | + name: group-objectids-example |
| 128 | +spec: |
| 129 | + compositeTypeRef: |
| 130 | + apiVersion: example.crossplane.io/v1 |
| 131 | + kind: XR |
| 132 | + pipeline: |
| 133 | + - step: get-group-objectids |
| 134 | + functionRef: |
| 135 | + name: function-msgraph |
| 136 | + input: |
| 137 | + apiVersion: msgraph.fn.crossplane.io/v1alpha1 |
| 138 | + kind: Input |
| 139 | + queryType: GroupObjectIDs |
| 140 | + groups: |
| 141 | + - "Developers" |
| 142 | + - "Operations" |
| 143 | + - "Security" |
| 144 | + target: "status.groupObjectIDs" |
| 145 | + skipQueryWhenTargetHasData: true |
| 146 | + credentials: |
| 147 | + - name: azure-creds |
| 148 | + source: Secret |
| 149 | + secretRef: |
| 150 | + namespace: crossplane-system |
| 151 | + name: azure-account-creds |
107 | 152 | ``` |
108 | 153 |
|
109 | | -## Mitigating Azure API throttling |
110 | | -
|
111 | | -If you encounter Azure API throttling, you can reduce the number of queries |
112 | | -using the optional `skipQueryWhenTargetHasData` flag: |
| 154 | +### Get Service Principal Details |
113 | 155 |
|
114 | 156 | ```yaml |
115 | | - - step: query-azresourcegraph |
| 157 | +apiVersion: example.crossplane.io/v1 |
| 158 | +kind: Composition |
| 159 | +metadata: |
| 160 | + name: service-principal-example |
| 161 | +spec: |
| 162 | + compositeTypeRef: |
| 163 | + apiVersion: example.crossplane.io/v1 |
| 164 | + kind: XR |
| 165 | + pipeline: |
| 166 | + - step: get-service-principal-details |
116 | 167 | functionRef: |
117 | | - name: function-azresourcegraph |
| 168 | + name: function-msgraph |
118 | 169 | input: |
119 | | - apiVersion: azresourcegraph.fn.crossplane.io/v1beta1 |
| 170 | + apiVersion: msgraph.fn.crossplane.io/v1alpha1 |
120 | 171 | kind: Input |
121 | | - query: "Resources | project name, location, type, id| where type =~ 'Microsoft.Compute/virtualMachines' | order by name desc" |
122 | | - target: "status.azResourceGraphQueryResult" |
123 | | - skipQueryWhenTargetHasData: true # Optional: Set to true to skip query if target already contains data |
| 172 | + queryType: ServicePrincipalDetails |
| 173 | + servicePrincipals: |
| 174 | + - "MyServiceApp" |
| 175 | + - "ApiConnector" |
| 176 | + target: "status.servicePrincipalDetails" |
| 177 | + skipQueryWhenTargetHasData: true |
| 178 | + credentials: |
| 179 | + - name: azure-creds |
| 180 | + source: Secret |
| 181 | + secretRef: |
| 182 | + namespace: crossplane-system |
| 183 | + name: azure-account-creds |
124 | 184 | ``` |
125 | 185 |
|
126 | | -Use this option carefully, as it may lead to stale query results over time. |
| 186 | +## Input Configuration Options |
127 | 187 |
|
128 | | -## Explicit Subscriptions scope |
| 188 | +| Field | Type | Description | |
| 189 | +|-------|------|-------------| |
| 190 | +| `queryType` | string | Required. Type of query to perform. Valid values: `UserValidation`, `GroupMembership`, `GroupObjectIDs`, `ServicePrincipalDetails` | |
| 191 | +| `users` | []string | List of user principal names (email IDs) for user validation | |
| 192 | +| `group` | string | Single group name for group membership queries | |
| 193 | +| `groups` | []string | List of group names for group object ID queries | |
| 194 | +| `servicePrincipals` | []string | List of service principal names | |
| 195 | +| `queryRef` | string | Optional. Reference to retrieve the query from status or context. Format: `status.<field>` or `context.<field>` | |
| 196 | +| `target` | string | Required. Where to store the query results. Can be `status.<field>` or `context.<field>` | |
| 197 | +| `skipQueryWhenTargetHasData` | bool | Optional. When true, will skip the query if the target already has data | |
129 | 198 |
|
130 | | -It is possible to specify explicit subscriptions scope and override the one that |
131 | | -is coming from credentials |
| 199 | +## Result Targets |
| 200 | + |
| 201 | +Results can be stored in either XR Status or Composition Context: |
132 | 202 |
|
133 | 203 | ```yaml |
134 | | - kind: Input |
135 | | - query: "Resources | project name, location, type, id| where type =~ 'Microsoft.Compute/virtualMachines' | order by name desc" |
136 | | - subscriptions: |
137 | | - - 00000000-0000-0000-0000-000000000001 |
138 | | - - 00000000-0000-0000-0000-000000000002 |
139 | | - target: "status.azResourceGraphQueryResult" |
140 | | -``` |
| 204 | +# Store in XR Status |
| 205 | +target: "status.results" |
141 | 206 |
|
142 | | -There is also possible to use references from status and context. |
| 207 | +# Store in nested XR Status |
| 208 | +target: "status.nested.field.results" |
143 | 209 |
|
| 210 | +# Store in Composition Context |
| 211 | +target: "context.results" |
144 | 212 |
|
145 | | -```yaml |
146 | | -subscriptionsRef: status.subscriptions |
| 213 | +# Store in Environment |
| 214 | +target: "context.[apiextensions.crossplane.io/environment].results" |
147 | 215 | ``` |
148 | 216 |
|
149 | | -```yaml |
150 | | -subscriptionsRef: "context.[apiextensions.crossplane.io/environment].subscriptions" |
151 | | -``` |
| 217 | +## References |
152 | 218 |
|
153 | | -[azresourcegraph]: https://learn.microsoft.com/en-us/azure/governance/resource-graph/ |
154 | | -[azop]: https://marketplace.upbound.io/providers/upbound/provider-family-azure/latest |
155 | | -[examples]: ./example |
| 219 | +- [Microsoft Graph API Overview](https://learn.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0) |
| 220 | +- [User validation](https://learn.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=go) |
| 221 | +- [Group membership](https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=go) |
| 222 | +- [Group listing](https://learn.microsoft.com/en-us/graph/api/group-list?view=graph-rest-1.0&tabs=go) |
| 223 | +- [Service principal listing](https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list?view=graph-rest-1.0&tabs=http) |
0 commit comments