Skip to content

Commit 9efad2b

Browse files
authored
Add Rbac Access Denied Policy Info in Access logs (#3100)
* Add Rbac Access Denied Policy Info in Access logs * fix lint error Signed-off-by: gargnupur <[email protected]> * fix based on feedback Signed-off-by: gargnupur <[email protected]> * fix based on feedback Signed-off-by: gargnupur <[email protected]>
1 parent 900979a commit 9efad2b

13 files changed

+123
-2
lines changed

extensions/common/context.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@ void populateExtendedHTTPRequestInfo(RequestInfo* request_info) {
428428
getValue({"request", "url_path"}, &request_info->url_path);
429429
getValue({"request", "host"}, &request_info->url_host);
430430
getValue({"request", "scheme"}, &request_info->url_scheme);
431+
std::string response_details;
432+
getValue({"response", "code_details"}, &response_details);
433+
if (!response_details.empty()) {
434+
request_info->response_details = response_details;
435+
}
431436
}
432437

433438
void populateExtendedRequestInfo(RequestInfo* request_info) {
@@ -448,6 +453,11 @@ void populateExtendedRequestInfo(RequestInfo* request_info) {
448453
envoy_original_dst_host ? envoy_original_dst_host->toString() : "";
449454
getValue({"upstream", "transport_failure_reason"},
450455
&request_info->upstream_transport_failure_reason);
456+
std::string response_details;
457+
getValue({"connection", "termination_details"}, &response_details);
458+
if (!response_details.empty()) {
459+
request_info->response_details = response_details;
460+
}
451461
}
452462

453463
void populateTCPRequestInfo(bool outbound, RequestInfo* request_info) {

extensions/common/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ struct RequestInfo {
159159
// populateExtendedHTTPRequestInfo.
160160
std::string source_address;
161161
std::string destination_address;
162+
std::string response_details;
162163

163164
// Additional fields for access log.
164165
std::string route_name;

extensions/stackdriver/log/logger.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "extensions/stackdriver/common/constants.h"
1919
#include "google/logging/v2/log_entry.pb.h"
2020
#include "google/protobuf/util/time_util.h"
21+
#include "re2/re2.h"
2122

2223
#ifndef NULL_PLUGIN
2324
#include "api/wasm/cpp/proxy_wasm_intrinsics.h"
@@ -31,6 +32,13 @@ namespace Extensions {
3132
namespace Stackdriver {
3233
namespace Log {
3334
namespace {
35+
// Matches Rbac Access denied string.
36+
// It is of the format:
37+
// "rbac_access_denied_matched_policy[ns[NAMESPACE]-policy[POLICY]-rule[POLICY_INDEX]]"
38+
const RE2 rbac_denied_match(
39+
"rbac_access_denied_matched_policy\\[ns\\[(.*)\\]-policy\\[(.*)\\]-rule\\[("
40+
".*)\\]\\]");
41+
constexpr char kRbacAccessDenied[] = "AuthzDenied";
3442
void setSourceCanonicalService(
3543
const ::Wasm::Common::FlatNode& peer_node_info,
3644
google::protobuf::Map<std::string, std::string>* label_map) {
@@ -158,6 +166,21 @@ void fillExtraLabels(
158166
}
159167
}
160168

169+
bool fillAuthInfo(const std::string& response_details,
170+
google::protobuf::Map<std::string, std::string>* label_map) {
171+
std::string policy_name, policy_namespace, policy_rule_index;
172+
if (RE2::PartialMatch(response_details, rbac_denied_match, &policy_namespace,
173+
&policy_name, &policy_rule_index)) {
174+
(*label_map)["response_details"] = kRbacAccessDenied;
175+
(*label_map)["policy_name"] =
176+
absl::StrCat(policy_namespace, ".", policy_name);
177+
(*label_map)["policy_rule"] = policy_rule_index;
178+
return true;
179+
}
180+
181+
return false;
182+
}
183+
161184
} // namespace
162185

163186
using google::protobuf::util::TimeUtil;
@@ -341,6 +364,11 @@ void Logger::fillAndFlushLogEntry(
341364
(*label_map)["upstream_transport_failure_reason"] =
342365
request_info.upstream_transport_failure_reason;
343366
}
367+
if (!request_info.response_details.empty()) {
368+
if (!fillAuthInfo(request_info.response_details, label_map)) {
369+
(*label_map)["response_details"] = request_info.response_details;
370+
}
371+
}
344372
}
345373

346374
// Insert trace headers, if exist.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/fsnotify/fsnotify v1.4.9
1010
github.com/ghodss/yaml v1.0.0
1111
github.com/golang/protobuf v1.4.2
12+
github.com/google/go-cmp v0.5.0
1213
github.com/kr/pretty v0.1.0 // indirect
1314
github.com/prometheus/client_model v0.2.0
1415
github.com/prometheus/common v0.9.1

scripts/check-style.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ if [[ ! -x "${CLANG_FORMAT}" || "${CLANG_VERSION}" != "${CLANG_VERSION_REQUIRED}
3434
echo "Unsupported environment." ; exit 1 ;
3535
fi
3636

37-
LLVM_URL_PREFIX="https://https://github.com/llvm/llvm-project/releases/download/llvmorg"
37+
LLVM_URL_PREFIX="https://github.com/llvm/llvm-project/releases/download/llvmorg"
3838
echo "Downloading clang-format: ${LLVM_URL_PREFIX}-${CLANG_VERSION_REQUIRED}/clang+llvm-${CLANG_VERSION_REQUIRED}-${CLANG_BIN}"
3939
echo "Installing required clang-format ${CLANG_VERSION_REQUIRED} to ${CLANG_DIRECTORY}"
4040

test/envoye2e/inventory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ func init() {
4545
"TestStackdriverTCPMetadataExchange/BaseCase",
4646
"TestStackdriverTCPMetadataExchange/NoAlpn",
4747
"TestStackdriverAttributeGen",
48+
"TestStackdriverCustomAccessLog",
49+
"TestStackdriverRbacAccessDenied",
4850
"TestStatsPayload/Default/envoy.wasm.runtime.null",
4951
"TestStatsPayload/Customized/envoy.wasm.runtime.null",
5052
"TestStatsPayload/UseHostHeader/envoy.wasm.runtime.null",

test/envoye2e/stackdriver_plugin/stackdriver.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ import (
2323
"time"
2424

2525
"github.com/golang/protobuf/proto"
26+
"github.com/google/go-cmp/cmp"
2627
logging "google.golang.org/genproto/googleapis/logging/v2"
2728
monitoring "google.golang.org/genproto/googleapis/monitoring/v3"
29+
"google.golang.org/protobuf/testing/protocmp"
2830

2931
"istio.io/proxy/test/envoye2e/driver"
3032
"istio.io/proxy/test/envoye2e/env"
@@ -186,6 +188,10 @@ func (s *checkStackdriver) Run(p *driver.Params) error {
186188
for want := range s.lwant {
187189
log.Println(want)
188190
}
191+
// Adding more logs for debugging in case of failures.
192+
if diff := cmp.Diff(s.sd.ls, s.lwant, protocmp.Transform()); diff != "" {
193+
log.Printf("t diff: %v\ngot:\n %v\nwant:\n %v\n", diff, s.sd.ls, s.lwant)
194+
}
189195
return fmt.Errorf("failed to receive expected logs")
190196
}
191197
}

test/envoye2e/stackdriver_plugin/stackdriver_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,3 +832,66 @@ func TestStackdriverCustomAccessLog(t *testing.T) {
832832
t.Fatal(err)
833833
}
834834
}
835+
836+
func TestStackdriverRbacAccessDenied(t *testing.T) {
837+
t.Parallel()
838+
respCode := "403"
839+
logEntryCount := 5
840+
841+
params := driver.NewTestParams(t, map[string]string{
842+
"ServiceAuthenticationPolicy": "NONE",
843+
"DirectResponseCode": respCode,
844+
"SDLogStatusCode": respCode,
845+
"StackdriverRootCAFile": driver.TestPath("testdata/certs/stackdriver.pem"),
846+
"StackdriverTokenFile": driver.TestPath("testdata/certs/access-token"),
847+
"RbacAccessDenied": "true",
848+
}, envoye2e.ProxyE2ETests)
849+
850+
sdPort := params.Ports.Max + 1
851+
stsPort := params.Ports.Max + 2
852+
params.Vars["SDPort"] = strconv.Itoa(int(sdPort))
853+
params.Vars["STSPort"] = strconv.Itoa(int(stsPort))
854+
params.Vars["ClientMetadata"] = params.LoadTestData("testdata/client_node_metadata.json.tmpl")
855+
params.Vars["ServerMetadata"] = params.LoadTestData("testdata/server_node_metadata.json.tmpl")
856+
params.Vars["ClientHTTPFilters"] = driver.LoadTestData("testdata/filters/mx_outbound.yaml.tmpl")
857+
params.Vars["ServerHTTPFilters"] = driver.LoadTestData("testdata/filters/mx_inbound.yaml.tmpl") + "\n" +
858+
driver.LoadTestData("testdata/filters/rbac.yaml.tmpl") + "\n" +
859+
driver.LoadTestData("testdata/filters/stackdriver_inbound.yaml.tmpl")
860+
sd := &Stackdriver{Port: sdPort}
861+
intRespCode, _ := strconv.Atoi(respCode)
862+
if err := (&driver.Scenario{
863+
Steps: []driver.Step{
864+
&driver.XDS{},
865+
sd,
866+
&SecureTokenService{Port: stsPort},
867+
&driver.Update{Node: "client", Version: "0", Listeners: []string{
868+
params.LoadTestData("testdata/listener/client.yaml.tmpl"),
869+
}},
870+
&driver.Update{Node: "server", Version: "0", Listeners: []string{
871+
params.LoadTestData("testdata/listener/server.yaml.tmpl"),
872+
}},
873+
&driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/server.yaml.tmpl")},
874+
&driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/client.yaml.tmpl")},
875+
&driver.Sleep{Duration: 1 * time.Second},
876+
&driver.Repeat{
877+
N: logEntryCount,
878+
Step: &driver.HTTPCall{
879+
Port: params.Ports.ClientPort,
880+
ResponseCode: intRespCode,
881+
},
882+
},
883+
sd.Check(params,
884+
nil, []SDLogEntry{
885+
{
886+
LogBaseFile: "testdata/stackdriver/server_access_log.yaml.tmpl",
887+
LogEntryFile: []string{"testdata/stackdriver/server_access_log_entry.yaml.tmpl"},
888+
LogEntryCount: logEntryCount,
889+
},
890+
},
891+
nil, true,
892+
),
893+
},
894+
}).Run(params); err != nil {
895+
t.Fatal(err)
896+
}
897+
}

testdata/filters/rbac.yaml.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
rules:
77
action: DENY
88
policies:
9-
"test":
9+
ns[foo]-policy[httpbin-deny]-rule[0]:
1010
permissions:
1111
- any: true
1212
principals:

testdata/stackdriver/client_access_log_entry.yaml.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ labels:
5252
{{- end }}
5353
upstream_cluster: "server-outbound-cluster"
5454
route_name: client_route
55+
response_details: "via_upstream"
5556
severity: INFO

testdata/stackdriver/client_gateway_access_log_entry.yaml.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ labels:
2121
destination_canonical_revision: version-1
2222
destination_canonical_service: ratings
2323
log_sampled: "false"
24+
response_details: "via_upstream"
2425
upstream_cluster: "server-outbound-cluster"
2526
route_name: client_route
2627
severity: INFO

testdata/stackdriver/gateway_access_log_entry.yaml.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ labels:
2121
source_canonical_service: ratings
2222
source_canonical_revision: version-1
2323
log_sampled: "false"
24+
response_details: "via_upstream"
2425
upstream_cluster: "server-inbound-cluster"
2526
route_name: server_route
2627
severity: INFO

testdata/stackdriver/server_access_log_entry.yaml.tmpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,12 @@ labels:
4040
log_sampled: "false"
4141
{{- end }}
4242
upstream_cluster: "server-inbound-cluster"
43+
{{- if .Vars.RbacAccessDenied }}
44+
response_details: "AuthzDenied"
45+
policy_name: "foo.httpbin-deny"
46+
policy_rule: "0"
47+
{{- else }}
48+
response_details: "via_upstream"
4349
route_name: server_route
50+
{{- end }}
4451
severity: INFO

0 commit comments

Comments
 (0)