/
endpoint1.xml
164 lines (152 loc) · 5.58 KB
/
endpoint1.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<ProxyEndpoint name='endpoint1'>
<Description>Show how to call into GCP Logging</Description>
<HTTPProxyConnection>
<BasePath>/gcp-logging</BasePath>
<Properties/>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<FaultRules/>
<DefaultFaultRule name="default-fault-rule">
<Step>
<Name>AM-Inject-Proxy-Revision-Header</Name>
</Step>
<AlwaysEnforce>true</AlwaysEnforce>
</DefaultFaultRule>
<PreFlow name='PreFlow'>
<Request/>
<Response>
<Step>
<Name>AM-Clean-Request-Headers-From-Response</Name>
</Step>
<Step>
<Name>AM-Inject-Proxy-Revision-Header</Name>
</Step>
</Response>
</PreFlow>
<PostFlow name='PostFlow'>
<Request/>
<Response>
<!--
This sequence is for logging to GCP Logging (previously known as
"Stackdriver"). It's all done in the Response flow. Ideally it would
be PostClientFlow, invoked via a FlowHook. But at this time there is
no FlowHook for PostClientFlow.
GCP Logging exposes a REST API for writing log messages. Invoking it requires
a bearer access token.
Acquiring the token for GCP Logging involves an RFC7523 flow, in which
the client generates a JWT signed with his own private key, sends the JWT to
the OAuth service, and obtains an opaque access token in response. This access
token has an expiry of 1 hour. There are some stipulations for this JWT - its
expiry, its claims (scope, issuer), and the signer and algorithm. The Google
OAuth service will reject the request for a new token if any of these
requirements is not met.
The sequence here does these things:
- check the cache for a token.
- If not present, get a new one. And cache it.
- using the existing or new token, invoke GCP Logging to write a log message.
-->
<Step>
<!-- see if there is a viable token in cache -->
<Name>Cache-Get-GCP-Logging-Token</Name>
</Step>
<!--
It would be nice to be able to wrap a longer sequence of steps in one
condition. But that is currently not possible in Apigee. The
following steps with the Condition `gcplogging.token = null` all get
executed only if there was a cache miss.
-->
<Step>
<Name>KVM-Get-SAKey-JSON</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<Name>JS-Shred-SAKey-JSON</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<!-- no token? generate a JWT to send to the Google OAuth service -->
<Name>JWT-Generate-Signed-Token-for-RFC7523-Flow</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<!-- no token? send the request to the Google OAuth service -->
<Name>SC-Obtain-GCP-Logging-AccessToken</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<!-- no token? extract the new token and expiry from the response from the Google OAuth service -->
<Name>Extract-GCP-Logging-AccessToken</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<!-- no token? adjust the expiry downward to be conservative with cache TTL -->
<Name>JS-Adjust-Expiry</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<!-- check for failure (no new token) -->
<Name>RF-No-AccessToken</Name>
<Condition>(gcplogging.token = null) and (gcplogging.newtoken = null)</Condition>
</Step>
<Step>
<Name>JS-Reform-Expiry</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<Step>
<!-- new token? insert it into cache -->
<Name>Cache-Put-GCP-Logging-Token</Name>
<Condition>(gcplogging.token = null) and (gcplogging.newtoken != null)</Condition>
</Step>
<Step>
<!-- new token? copy it to the context variable we want -->
<Name>AM-Set-GCP-Logging-Token</Name>
<Condition>gcplogging.token = null</Condition>
</Step>
<!-- set the project id and the log ID -->
<Step>
<Name>AM-Set-GCP-Logging-Settings</Name>
</Step>
<Step>
<!-- finally, invoke the Logging API using a JS Callout -->
<Name>JS-Log-To-GCP-Logging</Name>
<Condition>request.header.usesc = null</Condition>
</Step>
<Step>
<!-- or conditionally, invoke the logging API via ServiceCallout -->
<Name>SC-Log-To-GCP-Logging</Name>
<Condition>request.header.usesc != null</Condition>
</Step>
</Response>
</PostFlow>
<Flows>
<Flow name='test 1'>
<!--
curl -i $endpoint/gcp-logging/t1 \
-H content-type:application/json \
-d '{ "payload" : "YOUR MESSAGE GOES HERE" }'
-->
<Request>
<Step>
<Name>RF-InvalidContentType</Name>
<Condition>NOT (request.header.content-type =| "application/json")</Condition>
</Step>
<Step>
<Name>Extract-LogPayload</Name>
</Step>
</Request>
<Response>
<Step>
<Name>AM-Success</Name>
</Step>
</Response>
<Condition>(proxy.pathsuffix MatchesPath "/t1") and (request.verb = "POST")</Condition>
</Flow>
<Flow name='unknown request'>
<Request>
<Step><Name>RF-UnknownRequest</Name></Step>
</Request>
<Response/>
</Flow>
</Flows>
<RouteRule name='NoRouteRule'/>
</ProxyEndpoint>