Skip to content

Commit 71ef724

Browse files
authored
Merge pull request #11 from dheerajng/master
Citrix Istio Adaptor v1.2.1-beta
2 parents 34ab5c6 + e115de3 commit 71ef724

File tree

67 files changed

+1689
-2098
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1689
-2098
lines changed

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# STEP 1 build executable binary
22
FROM golang:1.12 as builder
3+
# https://unix.stackexchange.com/questions/96892/what-does-adduser-disabled-login-do
4+
RUN adduser --uid 32024 --disabled-login --gecos "" citrixuser
35

46
COPY . $GOPATH/src/citrix-istio-adaptor
57

@@ -12,6 +14,8 @@ RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go install -ldflags "-extldflags -stat
1214
FROM scratch
1315
# Copy our static executable
1416
COPY --from=builder /go/bin/istio-adaptor /go/bin/istio-adaptor
17+
COPY --from=builder /etc/passwd /etc/passwd
1518
COPY Version /etc/
1619

20+
USER citrixuser
1721
ENTRYPOINT ["/go/bin/istio-adaptor"]

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.PHONY: docker_build test clean coverage
2-
TARGETS=nsconfigengine adsclient istio-adaptor tests
2+
TARGETS=nsconfigengine adsclient istio-adaptor delayserver tests
33

44
build:
55
go install citrix-istio-adaptor/istio-adaptor
@@ -26,7 +26,7 @@ create_certs:
2626
sh tests/create_cert.sh
2727

2828
unit_test:
29-
go test -p 1 -race -timeout 1m -cover -coverprofile=unittestcov.out -v citrix-istio-adaptor/nsconfigengine citrix-istio-adaptor/adsclient citrix-istio-adaptor/istio-adaptor
29+
go test -p 1 -race -timeout 1m -cover -coverprofile=unittestcov.out -v citrix-istio-adaptor/nsconfigengine citrix-istio-adaptor/adsclient citrix-istio-adaptor/istio-adaptor citrix-istio-adaptor/delayserver
3030

3131
integration_test:
3232
go test -race -timeout 1m -cover -coverprofile=integrationtestcov.out -coverpkg=citrix-istio-adaptor/adsclient,citrix-istio-adaptor/nsconfigengine -v citrix-istio-adaptor/tests

README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ This repository contains various integrations of [Citrix ADC](https://www.citrix
2525
6. [Example: Deploying Bookinfo with Citrix ADC](#example)
2626
7. [Blogs](#blogs)
2727
8. [Release Notes](#release-notes)
28-
9. [Contributions and Development](#contributions)
28+
9. [Contributions](#contributions)
2929
10. [Questions](#questions)
3030
11. [Issues](#issues)
3131
12. [Code of Conduct](#code-of-conduct)
@@ -64,8 +64,6 @@ In Istio service mesh, Citrix ADC can act as an Ingress and/or sidecar proxy in
6464
| Citrix ADC | Envoyproxy | Yes |
6565
| Envoyproxy | Citrix ADC CPX | Yes |
6666

67-
You can deploy Citrix ADC with Istio using Kubernetes YAML or Helm charts. To deploy Citrix ADC with Istio using Kubernetes YAML, see [Deployment](deployment/README.md).
68-
6967
To deploy Citrix ADC with Istio using Helm charts, see the following links:
7068

7169
- [Deploy Citrix ADC as an Ingress Gateway using Helm charts](https://github.com/citrix/citrix-helm-charts/blob/master/citrix-adc-istio-ingress-gateway/README.md)
@@ -138,16 +136,16 @@ Follow this [link](https://github.com/citrix/citrix-helm-charts/blob/master/exam
138136
1. [Citrix ADC as an Istio Ingress Gateway: Part 1 Deployment](https://www.citrix.com/blogs/2019/11/13/citrix-adc-as-an-istio-ingress-gateway-part-1-deployment/)
139137
2. [Citrix ADC as an Istio Ingress Gateway: Part 2 Configuration](https://www.citrix.com/blogs/2019/11/14/citrix-adc-as-an-istio-ingress-gateway-part-2-configuration/)
140138
3. [Citrix ADC in OpenShift Service Mesh](https://blog.openshift.com/citrix-adc-in-openshift-service-mesh/)
139+
4. [Traffic Mirroring: Risk-free app upgrades in Istio with Citrix ADC](https://www.citrix.com/blogs/2020/04/29/traffic-mirroring-risk-free-app-upgrades-in-istio-with-citrix-adc/)
140+
5. [End-user authentication in Istio Service Mesh with Citrix](https://www.citrix.com/blogs/2020/03/19/end-user-authentication-in-istio-service-mesh-with-citrix/)
141141

142142
## <a name="release-notes">Release Notes</a>
143143

144144
Click [here](docs/release-notes.md) for the release notes of the latest Citrix `istio-adaptor`.
145145

146-
## <a name="contributions">Contributions and Development</a>
147-
148-
Refer [Contributions](CONTRIBUTING.md)
146+
## <a name="contributions">Contributions</a>
149147

150-
Please read the [Developer Guide](docs/developer-guide.md).
148+
Contributions are always welcome! Please read the [Developer Guide](docs/developer_guide.md).
151149

152150
## <a name="questions">Questions</a>
153151

Version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.0
1+
1.2.1

adsclient/ads_client.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,26 @@ type ldsAddHandlerType func(*configAdaptor, *xdsapi.Listener) map[string]interfa
4141
type ldsDelHandlerType func(*configAdaptor, string)
4242
type rdsAddHandlerType func(*configAdaptor, []*xdsapi.RouteConfiguration, interface{}) map[string]interface{}
4343

44+
//AdsDetails will define the members which will be read up at bootup time
45+
type AdsDetails struct {
46+
AdsServerURL string
47+
AdsServerSpiffeID string
48+
SecureConnect bool
49+
NodeID string
50+
ApplicationName string
51+
}
52+
53+
//NSDetails will define the members which will be read up at bootup time
54+
type NSDetails struct {
55+
NetscalerURL string
56+
NetscalerUsername string
57+
NetscalerPassword string
58+
NetscalerVIP string
59+
NetProfile string
60+
AnalyticsServerIP string
61+
LogProxyURL string
62+
}
63+
4464
type apiRequest struct {
4565
typeURL string
4666
versionInfo string
@@ -120,6 +140,7 @@ func cdsHandler(client *AdsClient, m *xdsapi.DiscoveryResponse) {
120140
cdsResource := &xdsapi.Cluster{}
121141
for _, resource := range m.Resources {
122142
if err := types.UnmarshalAny(resource, cdsResource); err != nil {
143+
log.Printf("[TRACE]:Could not find Unmarshal resources in CDS Handler")
123144
continue
124145
}
125146
clusterNames[cdsResource.Name] = true
@@ -155,6 +176,8 @@ func ldsHandler(client *AdsClient, m *xdsapi.DiscoveryResponse) {
155176
ldsResource := &xdsapi.Listener{}
156177
for _, resource := range m.Resources {
157178
if err := types.UnmarshalAny(resource, ldsResource); err != nil {
179+
log.Printf("[TRACE]:Could not find Unmarshal resources in LDS handler")
180+
continue
158181
}
159182
ldsResources[ldsResource.Name] = true
160183
dependentResources := client.ldsAddHandler(client.nsConfigAdaptor, ldsResource)
@@ -196,6 +219,8 @@ func edsHandler(client *AdsClient, m *xdsapi.DiscoveryResponse) {
196219
edsResource := &xdsapi.ClusterLoadAssignment{}
197220
for _, resource := range m.Resources {
198221
if err := types.UnmarshalAny(resource, edsResource); err != nil {
222+
log.Printf("[TRACE]:Could not find Unmarshal resources in EDS handler")
223+
continue
199224
}
200225
if _, ok := client.apiRequests[edsURL].resources[edsResource.GetClusterName()]; !ok {
201226
log.Printf("[ERROR]: received an EDS resource that we haven't yet subscribed for %s ... ignoring", edsResource.GetClusterName())
@@ -265,30 +290,27 @@ func (client *AdsClient) reloadCds() {
265290
stream.CloseSend()
266291
}
267292

268-
// NewAdsClient returns a new Aggregated Discovery Service client
269-
func NewAdsClient(adsServerURL string, adsServerSpiffeID string, secureConnect bool,
270-
nodeID string, applicationName string, netscalerURL string,
271-
netscalerUsername string, netscalerPassword string, netscalerVIP string,
272-
netProfile string, analyticsServerIP string, logProxyURL string) (*AdsClient, error) {
293+
//NewAdsClient returns a new Aggregated Discovery Service client
294+
func NewAdsClient(adsinfo *AdsDetails, nsinfo *NSDetails) (*AdsClient, error) {
273295
var err error
274296
adsClient := new(AdsClient)
275-
adsClient.adsServerURL = adsServerURL
276-
adsClient.adsServerSpiffeID = adsServerSpiffeID
277-
adsClient.secureConnect = secureConnect
278-
adsClient.nodeID = &envoy_api_v2_core.Node{Id: nodeID, Cluster: applicationName}
297+
adsClient.adsServerURL = adsinfo.AdsServerURL
298+
adsClient.adsServerSpiffeID = adsinfo.AdsServerSpiffeID
299+
adsClient.secureConnect = adsinfo.SecureConnect
300+
adsClient.nodeID = &envoy_api_v2_core.Node{Id: adsinfo.NodeID, Cluster: adsinfo.ApplicationName}
279301
adsClient.quit = make(chan int)
280302
adsClient.cdsAddHandler = clusterAdd
281303
adsClient.cdsDelHandler = clusterDel
282304
adsClient.ldsAddHandler = listenerAdd
283305
adsClient.ldsDelHandler = listenerDel
284306
adsClient.edsAddHandler = clusterEndpointUpdate
285307
adsClient.rdsAddHandler = routeUpdate
286-
s := strings.Split(adsServerURL, ":")
308+
s := strings.Split(adsinfo.AdsServerURL, ":")
287309
adsServerPort := "unknown"
288310
if len(s) > 1 {
289311
adsServerPort = s[1]
290312
}
291-
adsClient.nsConfigAdaptor, err = newConfigAdaptor(netscalerURL, netscalerUsername, netscalerPassword, adsServerPort, netscalerVIP, netProfile, analyticsServerIP, logProxyURL)
313+
adsClient.nsConfigAdaptor, err = newConfigAdaptor(nsinfo, adsServerPort)
292314
if err != nil {
293315
return nil, err
294316
}

adsclient/ads_client_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,30 @@ import (
2121

2222
func Test_StartClient(t *testing.T) {
2323
t.Logf("ads StartClient with unreachable secure ads grpc server")
24-
adsClient, err := NewAdsClient("loaclhost:15011", "", true, "ads_client_node_1", "test-app", env.GetNetscalerURL(), env.GetNetscalerUser(), env.GetNetscalerPassword(), "nsip", "", "", "ns-logproxy.citrix-system")
24+
nsinfo := new(NSDetails)
25+
adsinfo := new(AdsDetails)
26+
adsinfo.AdsServerURL = "localhost:15011"
27+
adsinfo.AdsServerSpiffeID = ""
28+
adsinfo.SecureConnect = false
29+
adsinfo.NodeID = "ads_client_node_1"
30+
adsinfo.ApplicationName = "test-app"
31+
nsinfo.NetscalerURL = env.GetNetscalerURL()
32+
nsinfo.NetscalerUsername = env.GetNetscalerUser()
33+
nsinfo.NetscalerPassword = env.GetNetscalerPassword()
34+
nsinfo.NetscalerVIP = "nsip"
35+
nsinfo.NetProfile = ""
36+
nsinfo.AnalyticsServerIP = ""
37+
nsinfo.LogProxyURL = "ns-logproxy.citrix-system"
38+
adsClient, err := NewAdsClient(adsinfo, nsinfo)
2539
if err != nil {
2640
t.Errorf("newAdsClient failed with %v", err)
2741
}
2842
adsClient.StartClient()
2943
time.Sleep(3 * time.Second)
3044
adsClient.StopClient()
3145
t.Logf("ads StartClient with unreachable insecure ads grpc server")
32-
adsClient, err = NewAdsClient("localhost:15010", "", false, "ads_client_node_1", "test-app", env.GetNetscalerURL(), env.GetNetscalerUser(), env.GetNetscalerPassword(), "nsip", "", "", "ns-logproxy.citrix-system")
46+
adsinfo.AdsServerURL = "localhost:15010"
47+
adsClient, err = NewAdsClient(adsinfo, nsinfo)
3348
if err != nil {
3449
t.Errorf("newAdsClient failed with %v", err)
3550
}

adsclient/ads_handler.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ limitations under the License.
1414
package adsclient
1515

1616
import (
17+
"citrix-istio-adaptor/delayserver"
1718
"citrix-istio-adaptor/nsconfigengine"
1819
"fmt"
1920
"log"
@@ -176,8 +177,15 @@ func clusterAdd(nsConfig *configAdaptor, cluster *xdsapi.Cluster, data interface
176177
}
177178
} else if cluster.GetType() == xdsapi.Cluster_ORIGINAL_DST { // Original Dst type has no load assignment or hosts! Extract info from name.
178179
staticAndDNSTypeClusterEndpointUpdate(nsConfig, cluster)
180+
} else if cluster.GetType() == xdsapi.Cluster_EDS {
181+
if cluster.GetEdsClusterConfig().GetServiceName() != "" {
182+
return cluster.GetEdsClusterConfig().GetServiceName()
183+
}
184+
if cluster.GetEdsClusterConfig().GetEdsConfig().GetAds() != nil {
185+
return cluster.Name
186+
}
179187
}
180-
return cluster.GetEdsClusterConfig().GetServiceName()
188+
return ""
181189
}
182190

183191
func clusterDel(nsConfig *configAdaptor, clusterName string) {
@@ -564,6 +572,7 @@ func getFault(typedPerFilterConfig map[string]*types.Any) nsconfigengine.Fault {
564572
}
565573
}
566574
if envoyFaultConfig.GetDelay() != nil {
575+
delayserver.StartDelayServer()
567576
percent := envoyFaultConfig.GetDelay().GetPercentage()
568577
numerator := percent.GetNumerator()
569578
den := envoyType.FractionalPercent_DenominatorType_name[int32(percent.GetDenominator())]

adsclient/ads_handler_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
xdsapi "github.com/envoyproxy/go-control-plane/envoy/api/v2"
2626
"github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
2727
v2Cluster "github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster"
28+
v2Core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
2829
envoyUtil "github.com/envoyproxy/go-control-plane/pkg/util"
2930
"github.com/gogo/protobuf/types"
3031
)
@@ -134,6 +135,7 @@ func Test_clusterAdd(t *testing.T) {
134135
}
135136

136137
log.Println("HTTPS cluster add")
138+
cds.EdsClusterConfig = &xdsapi.Cluster_EdsClusterConfig{EdsConfig: &v2Core.ConfigSource{ConfigSourceSpecifier: &v2Core.ConfigSource_Ads{Ads: &v2Core.AggregatedConfigSource{}}}}
137139
cds.CircuitBreakers = &v2Cluster.CircuitBreakers{Thresholds: []*v2Cluster.CircuitBreakers_Thresholds{&v2Cluster.CircuitBreakers_Thresholds{MaxConnections: &types.UInt32Value{Value: uint32(500)}, MaxRequests: &types.UInt32Value{Value: uint32(750)}}}}
138140
cds.MaxRequestsPerConnection = &types.UInt32Value{Value: uint32(100)}
139141
cds.TlsContext = &auth.UpstreamTlsContext{CommonTlsContext: env.MakeTLSContext("/etc/certs/server-cert.crt", "/etc/certs/server-key.key", "")}

adsclient/nsconf_adaptor.go

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ package adsclient
1616
import (
1717
"citrix-istio-adaptor/nsconfigengine"
1818
"container/list"
19+
"crypto/rand"
20+
"crypto/sha256"
1921
"fmt"
2022
"io/ioutil"
2123
"log"
@@ -45,7 +47,9 @@ const (
4547
edsAdd
4648
rdsAdd
4749
//MSS for setting various tcp profiles
48-
MSS = 1410
50+
MSS = 1410
51+
cpxConnRetries = 60
52+
vpxConnRetries = 3
4953
)
5054

5155
type configBlock struct {
@@ -73,33 +77,58 @@ type configAdaptor struct {
7377
analyticsProfiles []string // Two analyticspofile needed. One for TCP Insight, one for Web Insight
7478
}
7579

76-
func newConfigAdaptor(url, username, password, adsServerPort, vserverIP, netProfile, analyticsServerIP, logProxyURL string) (*configAdaptor, error) {
80+
// Check if the given ADC is CPX or VPX/MPX
81+
func isCPX(url string) bool {
82+
if strings.Contains(url, "localhost") || strings.Contains(url, localHostIP) {
83+
return true
84+
}
85+
return false
86+
}
87+
88+
func newConfigAdaptor(nsinfo *NSDetails, adsServerPort string) (*configAdaptor, error) {
7789
configAdaptor := new(configAdaptor)
7890
configAdaptor.adsServerPort = adsServerPort
79-
configAdaptor.vserverIP = vserverIP
80-
configAdaptor.netProfile = netProfile
91+
configAdaptor.vserverIP = nsinfo.NetscalerVIP
92+
configAdaptor.netProfile = nsinfo.NetProfile
8193
configAdaptor.configs = list.New()
8294
configAdaptor.cdsHash = make(map[string]*list.Element)
8395
configAdaptor.edsHash = make(map[string]*list.Element)
8496
configAdaptor.ldsHash = make(map[string]*list.Element)
8597
configAdaptor.rdsHash = make(map[string]*list.Element)
8698
configAdaptor.quit = make(chan bool)
87-
configAdaptor.analyticsServerIP = analyticsServerIP
88-
configAdaptor.logProxyURL = logProxyURL
99+
configAdaptor.analyticsServerIP = nsinfo.AnalyticsServerIP
100+
configAdaptor.logProxyURL = nsinfo.LogProxyURL
89101
var err error
90-
configAdaptor.client, err = netscaler.NewNitroClientFromParams(netscaler.NitroParams{Url: url, Username: username, Password: password})
102+
masterkey := make([]byte, 32)
103+
_, err = rand.Read(masterkey)
91104
if err != nil {
105+
log.Printf("[ERROR]: Could not generate cryptographically secure random number")
92106
return nil, err
93107
}
94-
for {
108+
// 32-byte key will be derived using PBKDF2 which uses 8-byte cryptographic salt and SHA256 hash function in 1000 iterations.
109+
keyspec := netscaler.NewKeyspec(masterkey, 8, 1000, 32, sha256.New) // Saltsize: 8, Iterations: 1000, Key-length: 32, HMAC: SHA256
110+
configAdaptor.client, err = netscaler.NewNitroClientFromParams(netscaler.NitroParams{Url: nsinfo.NetscalerURL, Username: nsinfo.NetscalerUsername, Password: nsinfo.NetscalerPassword, Keyspec: keyspec})
111+
if err != nil {
112+
return nil, err
113+
}
114+
i := 0
115+
connRetries := vpxConnRetries
116+
if isCPX(nsinfo.NetscalerURL) {
117+
connRetries = cpxConnRetries
118+
}
119+
for i = 0; i < connRetries; i++ {
95120
nsip, err := configAdaptor.getNitroObject(netscaler.Nsip.Type(), map[string]string{"type": "NSIP"})
96121
if err == nil {
97122
configAdaptor.nsip = nsip["ipaddress"].(string)
98123
break
99124
}
100125
time.Sleep(1 * time.Second)
101126
}
102-
if strings.Contains(url, "localhost") || strings.Contains(url, "127.0.0.1") {
127+
if i == connRetries {
128+
log.Println("[ERROR]: Could not establish connectivity with the ADC. Exiting!")
129+
return nil, fmt.Errorf("Connection establishment with ADC is unsuccessful")
130+
}
131+
if isCPX(nsinfo.NetscalerURL) {
103132
err = configAdaptor.sidecarBootstrapConfig()
104133
if err != nil {
105134
return nil, err
@@ -113,11 +142,7 @@ func newConfigAdaptor(url, username, password, adsServerPort, vserverIP, netProf
113142
if err != nil {
114143
log.Println("[WARN] Logproxy related config is not successful. Err = ", err)
115144
}
116-
if strings.Contains(url, "localhost") || strings.Contains(url, "127.0.0.1") {
117-
/* Citrix ADC CPX Case Saving the initial bootstrap configuration */
118-
configAdaptor.client.SaveConfig()
119-
}
120-
if vserverIP == "nsip" {
145+
if nsinfo.NetscalerVIP == "nsip" {
121146
configAdaptor.vserverIP = configAdaptor.nsip
122147
}
123148
build, err := configAdaptor.client.FindResource(netscaler.Nsversion.Type(), "")

adsclient/nsconf_adaptor_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ package adsclient
1515

1616
import (
1717
"citrix-istio-adaptor/tests/env"
18-
"github.com/chiradeep/go-nitro/netscaler"
1918
"log"
2019
"strings"
2120
"testing"
21+
22+
"github.com/chiradeep/go-nitro/netscaler"
2223
)
2324

2425
func init() {
@@ -68,7 +69,15 @@ func verifyModes(t *testing.T, client *netscaler.NitroClient, modes []string) {
6869
func Test_bootstrapConfig(t *testing.T) {
6970
t.Log("Verify BootStrap Config")
7071
var err interface{}
71-
configAd, err := newConfigAdaptor(env.GetNetscalerURL(), env.GetNetscalerUser(), env.GetNetscalerPassword(), "15010", "", "k8s", "", "ns-logproxy.citrix-system")
72+
nsinfo := new(NSDetails)
73+
nsinfo.NetscalerURL = env.GetNetscalerURL()
74+
nsinfo.NetscalerUsername = env.GetNetscalerUser()
75+
nsinfo.NetscalerPassword = env.GetNetscalerPassword()
76+
nsinfo.NetscalerVIP = ""
77+
nsinfo.NetProfile = "k8s"
78+
nsinfo.AnalyticsServerIP = ""
79+
nsinfo.LogProxyURL = "ns-logproxy.citrix-system"
80+
configAd, err := newConfigAdaptor(nsinfo, "15010")
7281
if err != nil {
7382
t.Errorf("Unable to get a config adaptor. newConfigAdaptor failed with %v", err)
7483
}

0 commit comments

Comments
 (0)