Skip to content

Commit

Permalink
Merge pull request #287 from gardener/fix-infoblox-cert-pool
Browse files Browse the repository at this point in the history
Update infoblox client and fix infoblox cert pool
  • Loading branch information
MartinWeindel authored Nov 23, 2022
2 parents e49965e + 160b071 commit 631fe07
Show file tree
Hide file tree
Showing 24 changed files with 2,042 additions and 1,569 deletions.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/go-openapi/strfmt v0.21.2
github.com/gophercloud/gophercloud v0.24.0
github.com/gophercloud/utils v0.0.0-20220307143606-8e7800759d16
github.com/infobloxopen/infoblox-go-client/v2 v2.0.0
github.com/infobloxopen/infoblox-go-client/v2 v2.1.0
github.com/miekg/dns v1.1.44
github.com/netlify/open-api v1.1.0
github.com/onsi/ginkgo/v2 v2.1.6
Expand Down Expand Up @@ -137,3 +137,6 @@ require (
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

// need open PR https://github.com/infobloxopen/infoblox-go-client/pull/195
replace github.com/infobloxopen/infoblox-go-client/v2 => github.com/MartinWeindel/infoblox-go-client/v2 v2.0.0-20221122085954-b7d80ebb106b
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/MartinWeindel/infoblox-go-client/v2 v2.0.0-20221122085954-b7d80ebb106b h1:5ltgdUOqRohN2Z/Xg8D0XUq2/Dir5kHvutd8CIkMZis=
github.com/MartinWeindel/infoblox-go-client/v2 v2.0.0-20221122085954-b7d80ebb106b/go.mod h1:+lznx4ASBSUZ2i6qwlgyn0v3eKDxBHNU5aRJzghAFbw=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
Expand Down Expand Up @@ -501,8 +503,6 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/infobloxopen/infoblox-go-client/v2 v2.0.0 h1:SoGI4PkU2zxGU2SCtpZA7rhd2GyNPsVuE1Ydno6B0Y8=
github.com/infobloxopen/infoblox-go-client/v2 v2.0.0/go.mod h1:+lznx4ASBSUZ2i6qwlgyn0v3eKDxBHNU5aRJzghAFbw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
Expand Down
42 changes: 18 additions & 24 deletions pkg/controller/provider/infoblox/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@
package infoblox

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"

Expand All @@ -34,17 +32,19 @@ import (

type access struct {
ibclient.IBConnector
metrics provider.Metrics
view string
requestBuilder ibclient.HttpRequestBuilder
metrics provider.Metrics
view string
}

var _ raw.Executor = (*access)(nil)

func NewAccess(client ibclient.IBConnector, view string, metrics provider.Metrics) *access {
func NewAccess(client ibclient.IBConnector, requestBuilder ibclient.HttpRequestBuilder, view string, metrics provider.Metrics) *access {
return &access{
IBConnector: client,
metrics: metrics,
view: view,
IBConnector: client,
requestBuilder: requestBuilder,
metrics: metrics,
view: view,
}
}

Expand Down Expand Up @@ -90,11 +90,11 @@ func (this *access) NewRecord(fqdn string, rtype string, value string, zone prov
if n, err := strconv.Unquote(value); err == nil && !strings.Contains(value, " ") {
value = n
}
record = (*RecordTXT)(ibclient.NewRecordTXT(ibclient.RecordTXT{
Name: fqdn,
Text: value,
View: this.view,
}))
r := ibclient.NewEmptyRecordTXT()
r.Name = fqdn
r.Text = value
r.View = this.view
record = (*RecordTXT)(r)
}
if record != nil {
record.SetTTL(int(ttl))
Expand All @@ -104,27 +104,21 @@ func (this *access) NewRecord(fqdn string, rtype string, value string, zone prov

func (this *access) GetRecordSet(dnsName, rtype string, zone provider.DNSHostedZone) (raw.RecordSet, error) {
this.metrics.AddZoneRequests(zone.Id().ID, provider.M_LISTRECORDS, 1)
c := this.IBConnector.(*ibclient.Connector)

if rtype != dns.RS_TXT {
return nil, fmt.Errorf("record type %s not supported for GetRecord", rtype)
}

execRequest := func(forceProxy bool) ([]byte, error) {
rt := ibclient.NewRecordTXT(ibclient.RecordTXT{})
urlStr := c.RequestBuilder.BuildUrl(ibclient.GET, rt.ObjectType(), "", rt.ReturnFields(), &ibclient.QueryParams{})
urlStr += "&name=" + dnsName
if forceProxy {
urlStr += "&_proxy_search=GM"
}
req, err := http.NewRequest("GET", urlStr, new(bytes.Buffer))
rt := ibclient.NewEmptyRecordTXT()
queryParams := ibclient.NewQueryParams(forceProxy, map[string]string{"name": dnsName, "view": this.view, "zone": zone.Key()})
req, err := this.requestBuilder.BuildRequest(ibclient.GET, rt, "", queryParams)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(c.HostConfig.Username, c.HostConfig.Password)

return c.Requestor.SendRequest(req)
requestor := &ibclient.WapiHttpRequestor{}
return requestor.SendRequest(req)
}

resp, err := execRequest(false)
Expand Down
107 changes: 53 additions & 54 deletions pkg/controller/provider/infoblox/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ package infoblox

import (
"context"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"os"
"strconv"

"github.com/gardener/controller-manager-library/pkg/logger"
Expand Down Expand Up @@ -115,9 +114,12 @@ func NewHandler(config *provider.DNSHandlerConfig) (provider.DNSHandler, error)
config.Logger.Infof("creating infoblox handler for %s", *infobloxConfig.Host)

hostConfig := ibclient.HostConfig{
Host: *infobloxConfig.Host,
Port: strconv.Itoa(*infobloxConfig.Port),
Version: *infobloxConfig.Version,
Host: *infobloxConfig.Host,
Port: strconv.Itoa(*infobloxConfig.Port),
Version: *infobloxConfig.Version,
}

authCfg := ibclient.AuthConfig{
Username: username,
Password: password,
}
Expand All @@ -127,25 +129,17 @@ func NewHandler(config *provider.DNSHandlerConfig) (provider.DNSHandler, error)
verify = strconv.FormatBool(*infobloxConfig.SSLVerify)
}

if infobloxConfig.CaCert != nil && verify == "true" {
tmpfile, err := ioutil.TempFile("", "cacert")
if err != nil {
return nil, fmt.Errorf("cannot create temporary file for cacert: %w", err)
}
defer os.Remove(tmpfile.Name())
if _, err := tmpfile.Write([]byte(*infobloxConfig.CaCert)); err != nil {
return nil, fmt.Errorf("cannot write temporary file for cacert: %w", err)
}
if err := tmpfile.Close(); err != nil {
return nil, fmt.Errorf("cannot close temporary file for cacert: %w", err)
}
verify = tmpfile.Name()
}
transportConfig := ibclient.NewTransportConfig(
verify,
*infobloxConfig.RequestTimeout,
*infobloxConfig.PoolConnections,
)
if infobloxConfig.CaCert != nil && verify == "true" {
transportConfig.CertPool, err = h.createCertPool([]byte(*infobloxConfig.CaCert))
if err != nil {
return nil, fmt.Errorf("cannot create cert pool for cacert: %w", err)
}
}
if infobloxConfig.ProxyURL != nil && *infobloxConfig.ProxyURL != "" {
u, err := url.Parse(*infobloxConfig.ProxyURL)
if err != nil {
Expand All @@ -154,17 +148,21 @@ func NewHandler(config *provider.DNSHandlerConfig) (provider.DNSHandler, error)
transportConfig.ProxyUrl = u
}

var requestBuilder ibclient.HttpRequestBuilder = &ibclient.WapiRequestBuilder{}
rb, err := ibclient.NewWapiRequestBuilder(hostConfig, authCfg)
if err != nil {
return nil, err
}
var requestBuilder ibclient.HttpRequestBuilder = rb
if infobloxConfig.MaxResults != 0 {
// wrap request builder which sets _max_results parameter on GET requests
requestBuilder = NewMaxResultsRequestBuilder(infobloxConfig.MaxResults, requestBuilder)
}
client, err := ibclient.NewConnector(hostConfig, transportConfig, requestBuilder, &ibclient.WapiHttpRequestor{})
client, err := ibclient.NewConnector(hostConfig, authCfg, transportConfig, requestBuilder, &ibclient.WapiHttpRequestor{})
if err != nil {
return nil, err
}

h.access = NewAccess(client, *h.infobloxConfig.View, config.Metrics)
h.access = NewAccess(client, requestBuilder, *h.infobloxConfig.View, config.Metrics)

h.ZoneCache, err = config.ZoneCacheFactory.CreateZoneCache(provider.CacheZonesOnly, config.Metrics, h.getZones, h.getZoneState)
if err != nil {
Expand All @@ -182,7 +180,7 @@ func (h *Handler) getZones(cache provider.ZoneCache) (provider.DNSHostedZones, e
h.config.Metrics.AddGenericRequests(provider.M_LISTZONES, 1)
obj := ibclient.NewZoneAuth(ibclient.ZoneAuth{})
err := h.access.GetObject(obj, "", &ibclient.QueryParams{}, &raw)
if err != nil {
if filterNotFound(err) != nil {
return nil, err
}

Expand All @@ -196,14 +194,10 @@ func (h *Handler) getZones(cache provider.ZoneCache) (provider.DNSHostedZones, e

h.config.Metrics.AddZoneRequests(z.Ref, provider.M_LISTRECORDS, 1)
var resN []RecordNS
objN := ibclient.NewRecordNS(
ibclient.RecordNS{
Zone: z.Fqdn,
View: *h.infobloxConfig.View,
},
)
err = h.access.GetObject(objN, "", &ibclient.QueryParams{}, &resN)
if err != nil {
objN := ibclient.NewRecordNS(ibclient.RecordNS{})
params := ibclient.NewQueryParams(false, map[string]string{"view": *h.infobloxConfig.View, "zone": z.Fqdn})
err = h.access.GetObject(objN, "", params, &resN)
if filterNotFound(err) != nil {
return nil, fmt.Errorf("could not fetch NS records from zone '%s': %s", z.Fqdn, err)
}
forwarded := []string{}
Expand All @@ -222,13 +216,12 @@ func (h *Handler) getZoneState(zone provider.DNSHostedZone, cache provider.ZoneC
state := raw.NewState()
rt := provider.M_LISTRECORDS

params := ibclient.NewQueryParams(false, map[string]string{"view": *h.infobloxConfig.View, "zone": zone.Key()})

h.config.Metrics.AddZoneRequests(zone.Id().ID, rt, 1)
var resA []RecordA
objA := ibclient.NewEmptyRecordA()
objA.Zone = zone.Key()
objA.View = *h.infobloxConfig.View
err := h.access.GetObject(objA, "", &ibclient.QueryParams{}, &resA)
if err != nil {
err := h.access.GetObject(ibclient.NewEmptyRecordA(), "", params, &resA)
if filterNotFound(err) != nil {
return nil, fmt.Errorf("could not fetch A records from zone '%s': %s", zone.Key(), err)
}
for _, res := range resA {
Expand All @@ -237,11 +230,8 @@ func (h *Handler) getZoneState(zone provider.DNSHostedZone, cache provider.ZoneC

h.config.Metrics.AddZoneRequests(zone.Id().ID, rt, 1)
var resAAAA []RecordAAAA
objAAAA := ibclient.NewEmptyRecordAAAA()
objAAAA.Zone = zone.Key()
objAAAA.View = *h.infobloxConfig.View
err = h.access.GetObject(objAAAA, "", &ibclient.QueryParams{}, &resAAAA)
if err != nil {
err = h.access.GetObject(ibclient.NewEmptyRecordAAAA(), "", params, &resAAAA)
if filterNotFound(err) != nil {
return nil, fmt.Errorf("could not fetch AAAA records from zone '%s': %s", zone.Key(), err)
}
for _, res := range resAAAA {
Expand All @@ -250,11 +240,8 @@ func (h *Handler) getZoneState(zone provider.DNSHostedZone, cache provider.ZoneC

h.config.Metrics.AddZoneRequests(zone.Id().ID, rt, 1)
var resC []RecordCNAME
objC := ibclient.NewEmptyRecordCNAME()
objC.Zone = zone.Key()
objC.View = *h.infobloxConfig.View
err = h.access.GetObject(objC, "", &ibclient.QueryParams{}, &resC)
if err != nil {
err = h.access.GetObject(ibclient.NewEmptyRecordCNAME(), "", params, &resC)
if filterNotFound(err) != nil {
return nil, fmt.Errorf("could not fetch CNAME records from zone '%s': %s", zone.Key(), err)
}
for _, res := range resC {
Expand All @@ -263,14 +250,8 @@ func (h *Handler) getZoneState(zone provider.DNSHostedZone, cache provider.ZoneC

h.config.Metrics.AddZoneRequests(zone.Id().ID, rt, 1)
var resT []RecordTXT
objT := ibclient.NewRecordTXT(
ibclient.RecordTXT{
Zone: zone.Key(),
View: *h.infobloxConfig.View,
},
)
err = h.access.GetObject(objT, "", &ibclient.QueryParams{}, &resT)
if err != nil {
err = h.access.GetObject(ibclient.NewEmptyRecordTXT(), "", params, &resT)
if filterNotFound(err) != nil {
return nil, fmt.Errorf("could not fetch TXT records from zone '%s': %s", zone.Key(), err)
}
for _, res := range resT {
Expand Down Expand Up @@ -325,3 +306,21 @@ func (h *Handler) DeleteRecordSet(logger logger.LogContext, zone provider.DNSHos
}
return nil
}

func (h *Handler) createCertPool(cert []byte) (*x509.CertPool, error) {
caPool := x509.NewCertPool()
if !caPool.AppendCertsFromPEM(cert) {
return nil, fmt.Errorf("cannot append certificate")
}
return caPool, nil
}

func filterNotFound(err error) error {
if err == nil {
return nil
}
if _, ok := err.(*ibclient.NotFoundError); ok {
return nil
}
return err
}
2 changes: 1 addition & 1 deletion pkg/controller/provider/infoblox/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (r *RecordTXT) GetDNSName() string { return r.Name }
func (r *RecordTXT) GetSetIdentifier() string { return "" }
func (r *RecordTXT) GetValue() string { return raw.EnsureQuotedText(r.Text) }
func (r *RecordTXT) GetTTL() int { return int(r.Ttl) }
func (r *RecordTXT) SetTTL(ttl int) { r.Ttl = uint(ttl); r.UseTtl = ttl != 0 }
func (r *RecordTXT) SetTTL(ttl int) { r.Ttl = uint32(ttl); r.UseTtl = ttl != 0 }
func (r *RecordTXT) Copy() raw.Record { n := *r; return &n }
func (r *RecordTXT) PrepareUpdate() raw.Record { n := *r; n.Zone = ""; n.View = ""; return &n }

Expand Down
61 changes: 61 additions & 0 deletions vendor/github.com/infobloxopen/infoblox-go-client/v2/CHANGELOG.rst

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 631fe07

Please sign in to comment.