Skip to content

Commit fc1c9e2

Browse files
authored
Resolves GCP API calls for monitoring.googleapis.com to set of IPs (#94)
Enables the prometheus sidecar to be configured to resolve GCP API calls to monitoring.googleapis.com to a specific set of IPs. Bool flag stackdriver.use-restricted-ips enables this functionality.
1 parent e00aaf5 commit fc1c9e2

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

cmd/stackdriver-prometheus-sidecar/main.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ import (
5858
"go.opencensus.io/plugin/ochttp"
5959
"go.opencensus.io/stats/view"
6060
"go.opencensus.io/tag"
61+
"google.golang.org/grpc/resolver"
62+
"google.golang.org/grpc/resolver/manual"
6163
kingpin "gopkg.in/alecthomas/kingpin.v2"
6264
)
6365

@@ -193,6 +195,8 @@ func main() {
193195
aggregations retrieval.CounterAggregatorConfig
194196
metricRenames map[string]string
195197
staticMetadata []scrape.MetricMetadata
198+
useRestrictedIps bool
199+
manualResolver *manual.Resolver
196200
monitoringBackends []string
197201

198202
logLevel promlog.AllowedLevel
@@ -213,6 +217,9 @@ func main() {
213217
a.Flag("stackdriver.api-address", "Address of the Stackdriver Monitoring API.").
214218
Default("https://monitoring.googleapis.com:443/").URLVar(&cfg.stackdriverAddress)
215219

220+
a.Flag("stackdriver.use-restricted-ips", "If true, send all requests through restricted VIPs (EXPERIMENTAL).").
221+
Default("false").BoolVar(&cfg.useRestrictedIps)
222+
216223
a.Flag("stackdriver.kubernetes.location", "Value of the 'location' label in the Kubernetes Stackdriver MonitoredResources.").
217224
StringVar(&cfg.kubernetesLabels.location)
218225

@@ -340,6 +347,19 @@ func main() {
340347
}
341348

342349
cfg.projectIdResource = fmt.Sprintf("projects/%v", *projectId)
350+
if cfg.useRestrictedIps {
351+
// manual.GenerateAndRegisterManualResolver generates a Resolver and a random scheme.
352+
// It also registers the resolver. rb.InitialAddrs adds the addresses we are using
353+
// to resolve GCP API calls to the resolver.
354+
cfg.manualResolver, _ = manual.GenerateAndRegisterManualResolver()
355+
// These IP addresses correspond to restricted.googleapis.com and are not expected to change.
356+
cfg.manualResolver.InitialAddrs([]resolver.Address{
357+
{Addr: "199.36.153.4:443"},
358+
{Addr: "199.36.153.5:443"},
359+
{Addr: "199.36.153.6:443"},
360+
{Addr: "199.36.153.7:443"},
361+
})
362+
}
343363
targetsURL, err := cfg.prometheusURL.Parse(targets.DefaultAPIEndpoint)
344364
if err != nil {
345365
panic(err)
@@ -381,6 +401,7 @@ func main() {
381401
projectIdResource: cfg.projectIdResource,
382402
url: cfg.stackdriverAddress,
383403
timeout: 10 * time.Second,
404+
manualResolver: cfg.manualResolver,
384405
},
385406
tailer,
386407
)
@@ -545,6 +566,7 @@ type clientFactory struct {
545566
projectIdResource string
546567
url *url.URL
547568
timeout time.Duration
569+
manualResolver *manual.Resolver
548570
}
549571

550572
func (f *clientFactory) New() stackdriver.StorageClient {
@@ -553,6 +575,7 @@ func (f *clientFactory) New() stackdriver.StorageClient {
553575
ProjectId: f.projectIdResource,
554576
URL: f.url,
555577
Timeout: f.timeout,
578+
Resolver: f.manualResolver,
556579
})
557580
}
558581

stackdriver/client.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"google.golang.org/grpc/codes"
3030
"google.golang.org/grpc/credentials"
3131
"google.golang.org/grpc/credentials/oauth"
32+
"google.golang.org/grpc/resolver/manual"
3233
"google.golang.org/grpc/status"
3334

3435
"github.com/go-kit/kit/log"
@@ -49,6 +50,7 @@ type Client struct {
4950
projectId string
5051
url *url.URL
5152
timeout time.Duration
53+
resolver *manual.Resolver
5254

5355
conn *grpc.ClientConn
5456
}
@@ -59,6 +61,7 @@ type ClientConfig struct {
5961
ProjectId string // The Stackdriver project id in "projects/name-or-number" format.
6062
URL *url.URL
6163
Timeout time.Duration
64+
Resolver *manual.Resolver
6265
}
6366

6467
// NewClient creates a new Client.
@@ -72,6 +75,7 @@ func NewClient(conf *ClientConfig) *Client {
7275
projectId: conf.ProjectId,
7376
url: conf.URL,
7477
timeout: conf.Timeout,
78+
resolver: conf.Resolver,
7579
}
7680
}
7781

@@ -120,6 +124,9 @@ func (c *Client) getConnection(ctx context.Context) (*grpc.ClientConn, error) {
120124
if len(c.url.Port()) > 0 {
121125
address = fmt.Sprintf("%s:%s", address, c.url.Port())
122126
}
127+
if c.resolver != nil {
128+
address = c.resolver.Scheme() + ":///" + address
129+
}
123130
conn, err := grpc.DialContext(ctx, address, dopts...)
124131
c.conn = conn
125132
return conn, err

stackdriver/client_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@
1414
package stackdriver
1515

1616
import (
17+
"bytes"
1718
"fmt"
1819
"net"
1920
"net/url"
2021
"strings"
2122
"testing"
2223
"time"
2324

25+
"github.com/go-kit/kit/log"
2426
monitoring "google.golang.org/genproto/googleapis/monitoring/v3"
2527
"google.golang.org/grpc"
2628
"google.golang.org/grpc/codes"
29+
"google.golang.org/grpc/resolver"
30+
"google.golang.org/grpc/resolver/manual"
2731
"google.golang.org/grpc/status"
2832
)
2933

@@ -114,3 +118,51 @@ func TestEmptyRequest(t *testing.T) {
114118
t.Fatal(err)
115119
}
116120
}
121+
122+
func TestResolver(t *testing.T) {
123+
grpcServer := grpc.NewServer()
124+
listener := newLocalListener()
125+
monitoring.RegisterMetricServiceServer(grpcServer, &metricServiceServer{nil})
126+
go grpcServer.Serve(listener)
127+
defer grpcServer.Stop()
128+
129+
logBuffer := &bytes.Buffer{}
130+
defer func() {
131+
if logBuffer.Len() > 0 {
132+
t.Log(logBuffer.String())
133+
}
134+
}()
135+
logger := log.NewLogfmtLogger(logBuffer)
136+
137+
// Without ?auth=false, the test fails with context deadline exceeded.
138+
serverURL, err := url.Parse("http://stackdriver.invalid?auth=false")
139+
if err != nil {
140+
t.Fatal(err)
141+
}
142+
143+
res, _ := manual.GenerateAndRegisterManualResolver()
144+
res.InitialAddrs([]resolver.Address{
145+
{Addr: listener.Addr().String()},
146+
})
147+
148+
c := NewClient(&ClientConfig{
149+
URL: serverURL,
150+
Timeout: time.Second,
151+
Resolver: res,
152+
Logger: logger,
153+
})
154+
155+
err = c.Store(&monitoring.CreateTimeSeriesRequest{
156+
TimeSeries: []*monitoring.TimeSeries{
157+
&monitoring.TimeSeries{},
158+
},
159+
})
160+
if err != nil {
161+
t.Fatal(err)
162+
}
163+
requestedTarget := c.conn.Target()
164+
if requestedTarget != c.resolver.Scheme()+":///stackdriver.invalid" {
165+
t.Errorf("ERROR: Remote address is %s, want stackdriver.invalid.",
166+
requestedTarget)
167+
}
168+
}

0 commit comments

Comments
 (0)