Can't get HTTPS working with Azure Front Door, AKS and Traefik - azure

I'm trying to setup Azure Front Door Premium in front of an AKS cluster with Traefik 2.5.3 as an ingress controller.
This is the relevant configuration in AFD:
I've got the following IngressRoutes and Certificate setup in AKS:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-domain-web
spec:
entryPoints:
- web
routes:
- match: Host(`my-domain.com`)
kind: Rule
services:
- name: whoami
port: 80
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-domain
spec:
entryPoints:
- websecure
routes:
- match: Host(`my-domain.com`)
kind: Rule
services:
- name: whoami
port: 80
tls:
secretName: my-domain-com-cert
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-domain-com-cert
spec:
commonName: my-domain.com
secretName: my-domain-com-cert
dnsNames:
- my-domain.com
issuerRef:
name: letsencrypt
kind: ClusterIssuer
Requesting over HTTP works:
> curl http://my-domain.com
Hostname: whoami-84d974bbd6-ff77m
IP: 127.0.0.1
IP: ::1
IP: 10.9.0.56
IP: fe80::4467:5bff:fee0:731b
RemoteAddr: 10.9.1.106:58076
GET / HTTP/1.1
Host: my-domain.com
User-Agent: curl/7.68.0
Accept: */*
Accept-Encoding: gzip
Via: 1.1 Azure
X-Azure-Clientip: <redacted>
X-Azure-Fdid: <redacted>
X-Azure-Ref: <redacted>
X-Azure-Requestchain: hops=1
X-Azure-Socketip: <redacted>
X-Forwarded-For: 10.9.0.4
X-Forwarded-Host: my-domain.com
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-6f49dccb4b-kv5c7
X-Real-Ip: 10.9.0.4
But requesting over HTTPS doesn't work:
> curl https://my-domain.com
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html xmlns='http://www.w3.org/1999/xhtml'><head><meta content='text/html; charset=utf-8' http-equiv='content-type'/><style type='text/css'>body {font-family:Arial; margin-left:40px; }img { border:0 none; }#content { margin-left: auto; margin-right: auto }#message h2 { font-size: 20px; font-weight: normal; color: #000000; margin: 34px 0px 0px 0px }#message p { font-size: 13px; color: #000000; margin: 7px 0px 0px0px}#errorref { font-size: 11px; color: #737373; margin-top: 41px }</style><title>Service unavailable</title></head><body><div id='content'><div id='message'><h2>Our services aren't available right now</h2><p>We're working to restore all services as soon as possible. Please check back soon.</p></div><div id='errorref'><span>0ksK6YgAAAADgd38yzqpIQasLDS0yNDFmYTUxODMyMjk=</span></div></div></body></html>%
In the Traefik logs I can see the following:
time="2022-06-28T09:05:22Z" level=debug msg="Serving default certificate for request: \"\""
time="2022-06-28T09:05:22Z" level=debug msg="http: TLS handshake error from 10.9.0.4:20734: EOF"
Here are the diagnostic logs from Azure Front Door:
I can't really figure out what the issue is... Could it be that the host header isn't propagated correctly so that Traefik doesn't know how to route it? I have enabled access logs in Traefik, but they don't log anything (I guess the request never reaches that far).
EDIT:
Turns out it's related to Traefik serving the request using the default self signed (invalid) Traefik cert.
I can get around this by setting a valid default cert in Traefik (using a TLSStore CRD), and disabling "Certificate subject name validation". I'm not sure what subject name is expected, but it isn't my-domain.com since that's what the cert contains.

Related

Kubernetes (AKS) : nginx ingress error 308 Permanent Redirect error. Private nginx Ingress controller

Over all description of what I am doing: I am using a private nginx ingress controller in AKS (Azure Kubernetes Service) and setting up Secrets Store CSI Driver to enable NGINX Ingress Controller with TLS using this doc: Doc1
Following are the steps I am doing as per the doc:
Deploying Secrets provider:
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-tls
spec:
provider: azure
secretObjects: # secretObjects defines the desired state of synced K8s secret objects
- secretName: ingress-tls-csi
type: kubernetes.io/tls
data:
- objectName: <CertName>
key: tls.key
- objectName: <CertName>
key: tls.crt
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: <GUIDForManagedIdentityProviderHavingAccessToKeyvault>
keyvaultName: <KeyvaultName> # the name of the AKV instance
objects: |
array:
- |
objectName: <CertName>
objectType: secret
tenantId: <GUIDForKeyVaultTenant> # the tenant ID of the AKV instance
Deploying a private nginx ingress controller using this documentation: Doc2
helm upgrade nginx-ingress ingress-nginx/ingress-nginx `
--install `
--version 4.1.3 `
--namespace ingress-nginx `
--set controller.replicaCount=2 `
--set controller.nodeSelector."kubernetes\.io/os"=linux `
--set controller.image.registry="ashwin.azurecr.io" `
--set controller.image.image="ingress-nginx/controller" `
--set controller.image.tag="v1.2.1" `
--set controller.image.digest="" `
--set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux `
--set controller.admissionWebhooks.patch.image.registry="ashwin.azurecr.io" `
--set controller.admissionWebhooks.patch.image.image="ingress-nginx/kube-webhook-certgen" `
--set controller.admissionWebhooks.patch.image.tag="v1.1.1" `
--set controller.admissionWebhooks.patch.image.digest="" `
--set defaultBackend.nodeSelector."kubernetes\.io/os"=linux `
--set defaultBackend.image.registry="ashwin.azurecr.io" `
--set defaultBackend.image.image="defaultbackend-amd64" `
--set defaultBackend.image.tag="1.5" `
--set defaultBackend.image.digest="" `
-f "..\..\manifests\internal-controller-tls.yaml" --debug
The ..\..\manifests\internal-controller-tls.yaml file has this content:
controller:
service:
loadBalancerIP: 10.0.0.11
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path: "/healthz"
extraVolumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-tls"
extraVolumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
Deployed the ingress having this configuration( Picked from here Doc1):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: healthcheck-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
tls:
- hosts:
- ingress.cluster.apaca.demo.com
secretName: ingress-tls-csi
rules:
- host: ingress.cluster.apaca.demo.com
http:
paths:
- path: /cluster-ingress-healthz(/|$)(.*)
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
- path: /(.*)
pathType: Prefix
backend:
service:
name: service2
port:
number: 80
After following the 3 steps I am seeing 308 Permanent Redirect when i do a curl command to the http endpoint of the ingress:
azadmin#acs-apaca-aksVm:~$ curl -v http://ingress.cluster.apaca.demo.com
* Rebuilt URL to: http://ingress.cluster.apaca.demo.com/
* Trying 10.0.0.11...
* TCP_NODELAY set
* Connected to ingress.cluster.apaca.demo.com (10.0.0.11) port 80 (#0)
> GET / HTTP/1.1
> Host: ingress.cluster.apaca.demo.com
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Date: Thu, 14 Jul 2022 04:28:53 GMT
< Content-Type: text/html
< Content-Length: 164
< Connection: keep-alive
< Location: https://ingress.cluster.apaca.demo.com
<
<html>
<head><title>308 Permanent Redirect</title></head>
<body>
<center><h1>308 Permanent Redirect</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host ingress.cluster.apaca.demo.com left intact
azadmin#acs-apaca-aksVm:~$
But when i put this additional annotation in kubernetes ingress, nginx.ingress.kubernetes.io/ssl-redirect: "false" the http endpoint shows the correct content
This is what i see when i do a curl to the http ingress endpoint:
azadmin#acs-apaca-aksVm:~$ curl -v http://ingress.cluster.apaca.demo.com
* Rebuilt URL to: http://ingress.cluster.apaca.demo.com/
* Trying 10.0.0.11...
* TCP_NODELAY set
* Connected to ingress.cluster.apaca.demo.com (10.0.0.11) port 80 (#0)
> GET / HTTP/1.1
> Host: ingress.cluster.apaca.demo.com
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 14 Jul 2022 04:33:34 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 617
< Connection: keep-alive
<
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="/static/default.css">
<title>WELCOME TO AZURE KUBERNETES SERVICE</title>
<script language="JavaScript">
function send(form){
}
</script>
</head>
<body>
<div id="container">
<form id="form" name="form" action="/"" method="post"><center>
<div id="logo">WELCOME TO AZURE KUBERNETES SERVICE</div>
<div id="space"></div>
<img src="/static/acs.png" als="acs logo">
<div id="form">
</div>
</div>
</body>
* Connection #0 to host ingress.cluster.apaca.demo.com left intact
</html>azadmin#acs-apaca-aksVm:~$
but with the additional annotation of nginx.ingress.kubernetes.io/ssl-redirect: "false" the requests will only be http. When i do a curl to the https endpoint for ingress.. I see this in both the cases (case 1: Annotation not added to the ingress, case 2: Annotation added to the ingress).
azadmin#acs-apaca-aksVm:~$ curl -v https://ingress.cluster.apaca.demo.com
* Rebuilt URL to: https://ingress.cluster.apaca.demo.com/
* Trying 10.0.0.11...
* TCP_NODELAY set
* Connected to ingress.cluster.apaca.demo.com (10.0.0.11) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* stopped the pause stream!
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
azadmin#acs-apaca-aksVm:~$
Please help me understand what should I change here so that the 308 redirects error go away and I can have successfull https connected to the ingress endpoint

How to link AKS ingress external IP to Azure DNS zone?

I'm attempting to add an ingress to my AKS cluster and link that to a domain I have purchased but the site always fails to load in the browser. It doesn't matter whether I use the IP address of DNS name, it fails all the same.
I have added a DNS zone and an entry that points to a frontend IP configuration on the load balancer.
This IP corresponds to the external IP of the ingress.
I can also run a curl request which appears to return details of my react application
curl -v -k --resolve oconnorevents.co.uk:443:20.90.138.208 https://oconnorevents.co.uk
* Added oconnorevents.co.uk:443:20.90.138.208 to DNS cache
* Hostname oconnorevents.co.uk was found in DNS cache
* Trying 20.90.138.208:443...
* Connected to oconnorevents.co.uk (20.90.138.208) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
* CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=oconnorevents.co.uk; O=aks-ingress-tls
* start date: May 18 18:41:04 2021 GMT
* expire date: May 18 18:41:04 2022 GMT
* issuer: CN=oconnorevents.co.uk; O=aks-ingress-tls
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x1c41bb41a30)
> GET / HTTP/2
> Host: oconnorevents.co.uk
> user-agent: curl/7.75.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< date: Tue, 18 May 2021 22:31:05 GMT
< content-type: text/html
< content-length: 3179
< last-modified: Tue, 18 May 2021 19:15:59 GMT
< etag: "60a4126f-c6b"
< accept-ranges: bytes
< strict-transport-security: max-age=15724800; includeSubDomains
<
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><title>React App</title><link href="/static/css/main.6dea0f05.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,a,i=r[0],c=r[1],l=r[2],s=0,p=[];s<i.length;s++)a=i[s],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&p.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var c=t[i];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{2:"edb3d180",4:"2f2d3220",5:"40109260"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=this["webpackJsonpoconnorevents.react"]=this["webpackJsonpoconnorevents.react"]||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var f=c;t()}([])</script><script src="/static/js/3.5e3399a8.chunk.js"></script><script src="/static/js/main.8eab695a.chunk.js"></script></body></html>* Connection #0 to host oconnorevents.co.uk left intact
This is the details of my ingress
Name: ingress
Namespace: default
Address: 20.90.138.208
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
TLS:
aks-ingress-tls terminates oconnorevents.co.uk
Rules:
Host Path Backends
---- ---- --------
oconnorevents.co.uk
/(.*) svc-oconnorevents-react:80 (10.244.0.41:80)
Annotations: kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: true
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 0s (x2 over 23s) nginx-ingress-controller Scheduled for sync
Normal Sync 0s (x2 over 23s) nginx-ingress-controller Scheduled for sync
This is the .yaml for my ingress...
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- oconnorevents.co.uk
secretName: aks-ingress-tls
rules:
- host: oconnorevents.co.uk
http:
paths:
- path: /(.*)
pathType: Prefix
backend:
service:
name: svc-oconnorevents-react
port:
number: 80
And this is the service and app that it's pointing to
apiVersion: v1
kind: Service
metadata:
name: svc-oconnorevents-react
labels:
version: dev
product: oconnorevents-react
spec:
selector:
app: oconnorevents-react
type: ClusterIP
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-oconnorevents-react
spec:
replicas: 1
selector:
matchLabels:
app: oconnorevents-react
template:
metadata:
labels:
app: oconnorevents-react
spec:
containers:
- name: oconnorevents-react
image: oconnorevents.azurecr.io/oconnoreventsreact:#{Build.BuildId}#
ports:
- containerPort: 80
resources:
limits:
cpu: "0.10"
imagePullSecrets:
- name: acr-secret
I feel I am close but where am I going wrong here?
What kind of error are you getting when accessing via a browser?
The curl request is succeeding because you’re explicitly ignoring the self-signed certificate with ‘-k’.

Why my Curl command is failing inside a docker container

I am running a python based server inside a container. I can access it inside my host machine
curl --header "Content-Type: application/json" --request POST --data '{"uid":"admin","password":"admin"}' http://localhost:9000/auth
Result:
{"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTA4Mjk1NDAsImlhdCI6MTU5MDgyNTk0MCwibmJmIjoxNTkwODI1OTQwLCJzdWIiOiJhZG1pbiJ9.iTexlDupUMYYrodw44GI9ZnsTXnl5MurAXq6JCfqM0A"}
But now i am trying to do same curl inside another container, But It gives me access denied error.
Note: Unnecessary use of -X or --request, POST is already inferred.
* Expire in 0 ms for 6 (transfer 0x564809d7ff50)
* Uses proxy env variable http_proxy == 'http://10.223.4.20:911'
* Trying 10.223.4.20...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x564809d7ff50)
* Connected to 10.223.4.20 (10.223.4.20) port 911 (#0)
> POST http://localhost:9000/auth HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.64.0
> Accept: */*
> Proxy-Connection: Keep-Alive
> Content-Type: application/json
> Content-Length: 34
>
* upload completely sent off: 34 out of 34 bytes
< HTTP/1.1 403 Forbidden
< Cache-Control: no-cache
< Pragma: no-cache
< Content-Type: text/html; charset=utf-8
< Proxy-Connection: Keep-Alive
< Connection: Keep-Alive
< Content-Length: 642
<
<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD>
<BODY>
<FONT face="Helvetica">
<big><strong></strong></big><BR>
</FONT>
<blockquote>
<TABLE border=0 cellPadding=1 width="80%">
<TR><TD>
<FONT face="Helvetica">
<big>Access Denied (policy_denied)</big>
<BR>
<BR>
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Helvetica">
Your system policy has denied access to the requested URL.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Helvetica">
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Helvetica" SIZE=2>
<BR>
For assistance, contact your network support team.
</FONT>
</TD></TR>
</TABLE>
</blockquote>
</FONT>
</BODY></HTML>
* Connection #0 to host 10.223.4.20 left intact
All the containers are mapped as network_mode: host.
Here is my Docker-compose.yml
version: '2'
services:
tacotron:
image: tacotron-image
network_mode: host
command: python3 runserver.py
tts_driver:
image: tts_driver
privileged: true
network_mode: host
environment:
- ASR_PUB_PORT=5555
- ASR_PUB_TOPIC=subnlptopic
- TTS_DRIVER_PUB_PORT=5556
- TTS_DRIVER_PUB_TOPIC=pubttstopic
command: python3 /app/TTSDriver.py
What i am doing wrong here?
Thanks
Akshay

Invoke node.js api from WSO2

I am trying to invoke a node.js REST api (http://localhost:3000/users) from WSO2 Api Mgmt on-prem configuration but it doesn't work. The node.js REST api works fine from a browser/Postman. When called from WSO2, it returns empty response.
Endpoint exposed from WSO2 AM is http://localhost:801/api/v1/users and it is supposed to call the node.js REST api. I tried to use the debug features in WSO2 and found that the call never reaches the node.js endpoint due to some very long exception dump displayed in the console.
I am using Authorization header for the WSO2 front and it seems to work fine.
Though I have worked a bit in node.js, I am super-new to WSO2. So any help will be much appreciated.
Edit: I am using WSO2 AM 1.9.0
Response body from WSO2 API console given below -
<html>
<head>
<title>Apache Tomcat/7.0.55 - Error report</title>
<style>
<!
--H1
{
font-family: Tahoma,Arial,sans-serif;
color: white;
background-color: #525D76;
font-size: 22px;
}
H2
{
font-family: Tahoma,Arial,sans-serif;
color: white;
background-color: #525D76;
font-size: 16px;
}
H3
{
font-family: Tahoma,Arial,sans-serif;
color: white;
background-color: #525D76;
font-size: 14px;
}
BODY
{
font-family: Tahoma,Arial,sans-serif;
color: black;
background-color: white;
}
B
{
font-family: Tahoma,Arial,sans-serif;
color: white;
background-color: #525D76;
}
P
{
font-family: Tahoma,Arial,sans-serif;
background: white;
color: black;
font-size: 12px;
}
A
{
color: black;
}
A.name
{
color: black;
}
HR
{
color: #525D76;
}
-- ></style>
</head>
<body>
<h1>
HTTP Status 405 - HTTP method GET is not supported by this URL</h1>
<hr size="1" noshade="noshade">
<p>
<b>type</b> Status report</p>
<p>
<b>message</b> <u>HTTP method GET is not supported by this URL</u></p>
<p>
<b>description</b> <u>The specified HTTP method is not allowed for the requested resource.</u></p>
<hr size="1" noshade="noshade">
<h3>
Apache Tomcat/7.0.55</h3>
</body>
</html>
Edit : API Manager log
[2015-06-23 14:36:04,903] INFO - HandlerUtils Massage Info: Transaction id=1499
743816386524554259 Message direction=IN Server name=192.168.1.5:9763 Timestam
p=1435050364903 Service name=__SynapseService Operation Name=mediate
[2015-06-23 14:36:04,906] DEBUG - HTTPEndpoint Sending message through endpoint
: admin--GetUsers_APIproductionEndpoint_0 resolving to address = http://127.0.0.
1:3000/users
[2015-06-23 14:36:04,909] DEBUG - HTTPEndpoint SOAPAction: null
[2015-06-23 14:36:04,910] DEBUG - HTTPEndpoint WSA-Action: null
[2015-06-23 14:36:04,926] INFO - HandlerUtils Massage Info: Transaction id=1499
743816386524554259 Message direction=OUT Server name=192.168.1.5:9763 Timesta
mp=1435050364926 Service name=__SynapseService Operation Name=mediate
Edit : Remaining details from API log
Curl
curl -X GET --header "Accept: application/json" --header "Authorization: Bearer 6a931d4fb2f6c85be750ee7cea8bc094" "https://localhost:9443/api/v1/users"
Request URL
https://localhost:9443/api/v1/users
Response Code
405
Response Headers
{
"date": "Tue, 23 Jun 2015 09:05:49 GMT",
"server": "WSO2 Carbon Server",
"content-type": "text/html;charset=utf-8",
"content-length": "1065",
"content-language": "en"
}
You have to check the GET checkbox value while giving the endpoint address.
Use this API sequence
<?xml version="1.0" encoding="UTF-8"?>
<api xmlns="http://ws.apache.org/ns/synapse"
name="nodejsAPI"
context="/api">
<resource methods="GET" protocol="http" uri-template="/v1/users">
<inSequence>
<log level="full"/>
<send>
<endpoint>
<http method="GET"
uri-template="http://localhost:3000/users/"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</resource>
</api>
Your API creation has probably had some issues, and therefore it has not been mapped correctly to your nodeJS REST endpoint.
In the API creation wizard, you have the option to test whether the API-M can reach your endpoint. This step can verify that there is no issue in connecting.
I have written a blog post on step by step process for your use case. Please follow these steps, and hopefully, it should work.
Make sure the URL pattern field and production endpoint field have correct values.

IIS: SSL Site not respond to all browsers/devices by https

I've installed a Geotrust certificate for my site, which run over IIS7. The certificate is correctly installed, but I am getting an unexpected result. When I make a request to a http://example.com, it Works well on every browser/device, but when I make a request to https://example.com, it only responds in some browsers/devices, examples:
- On the same PC respond well only in Firefox, but not in IE or Chrome.
- On others PCs not respond to any browsers.
- The strangest, in my Smartphone, not respond through wifi, but when I am connected over 3G the site respond properly to https.
- I also test in a labtop, via wifi the site dont respond, but if I share the 3g connection from the Smartphone to the labtop, the web Works properly.
EDIT: the result of the openssl command:
Loading 'screen' into random state - done
CONNECTED(000001C4)
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/C=ES/ST=Malaga/L=Malaga/O=domain/CN=www.domain.net/OU=domain
i:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G2
1 s:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G2
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIExjCCA66gAwIBAgIQeee0uwSySeNXOkI+BUoMMzANBgkqhkiG9w0BAQUFADBE
MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMU
...
doLsKI2R6RQA/7IcuTpKkvLF5wYKvmocPxYVg9FOoFvKV0wjWo6qlwsANPAVov+7
zFzZreROa7lBj8UH0IyYjLmBrbe1yMr/Cmg=
-----END CERTIFICATE-----
subject=/C=ES/ST=Malaga/L=Malaga/O=domain/CN=www.domain.net/OU=domain
issuer=/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G2
---
No client certificate CA names sent
---
SSL handshake has read 3405 bytes and written 645 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES128-SHA
Session-ID: D80B0000C341A313FBA6527E6576D1D71ACA71E680528EE880649C8166AA7C1B
Session-ID-ctx:
Master-Key: F1D5AB2E543959B3D100CC16365884DEFF06E56E3C57839A64088744FFCAEDCE
24B744836326E46828537C64884081B0
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1407168950
Timeout : 300 (sec)
Verify return code: 20 (unable to get local issuer certificate)
---
After some searching and testing some ideas I have not done anything and I'm going crazy. Any idea?
... but when I make a request to https://example.com, it only responds in some browsers/devices...
OK, the certificate chain looks OK. I grabbed your server's name out of the cert you posted for the tests below. You can run your certificate through openssl x509 and see the CN and SAN:
$ openssl x509 -in server-cert.pem -inform PEM -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
79:e7:b4:bb:04:b2:49:e3:57:3a:42:3e:05:4a:0c:33
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust SSL CA - G2
Validity
Not Before: Jun 11 00:00:00 2014 GMT
Not After : Jun 11 23:59:59 2015 GMT
Subject: C=ES, ST=Malaga, L=Malaga, O=Example, CN=www.example.com, OU=Example, LLC
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a2:f6:fd:b0:30:10:91:55:3f:ec:ce:fa:d8:9e:
84:cd:60:c4:dd:a8:f0:42:37:66:a9:98:80:35:d8:
...
13:db:e9:98:c5:1a:ac:31:50:70:e1:6e:8d:1f:2a:
7d:b5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:www.example.com, DNS:example.com
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 CRL Distribution Points:
Full Name:
URI:http://gb.symcb.com/gb.crl
X509v3 Certificate Policies:
Policy: 2.16.840.1.113733.1.7.54
CPS: https://d.symcb.com/cps
User Notice:
Explicit Text: https://d.symcb.com/rpa
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Authority Key Identifier:
keyid:11:4A:D0:73:39:D5:5B:69:08:5C:BA:3D:BF:64:9A:A8:8B:1C:55:BC
Authority Information Access:
OCSP - URI:http://gb.symcd.com
CA Issuers - URI:http://gb.symcb.com/gb.crt
Signature Algorithm: sha1WithRSAEncryption
52:60:0e:f3:c7:fb:16:49:cf:4f:7c:91:d9:c9:b9:d5:92:62:
75:c9:05:f1:b7:cf:ea:30:53:44:5d:a7:1e:c7:eb:fd:a9:ab:
...
e4:4e:6b:b9:41:8f:c5:07:d0:8c:98:8c:b9:81:ad:b7:b5:c8:
ca:ff:0a:68
You have both example.com and www.example.com. That is OK.
One small nitpick. Placing a DNS name in the Common Name (CN) is deprecated by both the IETF and CA/Browser forums. DNS names should be placed in the Subject Alternate Name (SAN). Put a friendly name in the CN because its usually displayed to the user.
The issue should not produce the problem you are experiencing. In fact, I use Startcom certificates for my web and mail server and have never had an issue.
Next, OpenSSL's "Verify return code: 20 (unable to get local issuer certificate)" complaint is because you are not using CAfile option with <Equifax Secure Certificate Authority>.pem. If interested, you can download it from GeoTrust Root Certificates. I'll use it below to ensure a "Verify return code: 0 (ok)".
Now, check this out (SSLv3):
$ echo -e "GET / HTTP/1.1\n" | openssl s_client -connect example.com:443 \
-ssl3 -ign_eof -CAfile Equifax_Secure_Certificate_Authority.pem
CONNECTED(00000003)
depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority
verify return:1
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify return:1
depth=1 C = US, O = GeoTrust Inc., CN = GeoTrust SSL CA - G2
verify return:1
depth=0 C = ES, ST = Malaga, L = Malaga, O = Example, LLC, CN = www.example.com, OU = Example, LLC
verify return:1
---
Certificate chain
0 s:/C=ES/ST=Malaga/L=Malaga/O=Example, LLC/CN=www.example.com/OU=Example, LLC
i:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G2
1 s:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G2
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
...
Start Time: 1407401571
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 07 Aug 2014 08:52:28 GMT
Connection: close
Content-Length: 334
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>
read:errno=0
And (TLS 1.0 with SNI):
$ echo -e "GET / HTTP/1.1\n" | openssl s_client -connect example.com:443 \
-tls1 -servername example.com -ign_eof -CAfile Equifax_Secure_Certificate_Authority.pem
CONNECTED(00000003)
...
Start Time: 1407401898
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 07 Aug 2014 08:57:55 GMT
Connection: close
Content-Length: 334
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>
read:errno=0
It does not appear to be Server Name Indication (SNI) related. I'm not sure SNI being honored at this point. Is this IIS 7.5 or below? IIS 8 provides SNI, and that might help the issue since the request will be routed immediately to the correct virtual domain in IIS.
Next, add a host header:
$ echo -e "GET / HTTP/1.1\nHost:example.com\n" | openssl s_client -connect example.com:443 \
-ssl3 -ign_eof -CAfile Equifax_Secure_Certificate_Authority.pem
CONNECTED(00000003)
...
Start Time: 1407402117
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
read R BLOCK
HTTP/1.1 302 Found
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Location: /Login/Login
Server: Microsoft-IIS/7.5
Set-Cookie: ASP.NET_SessionId=310xiuzver13lqoau0il0tsu; path=/; HttpOnly
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 07 Aug 2014 09:01:34 GMT
The 302 redirect looks wrong. Shouldn't that be a 301? See HTTP redirect: 301 (permanent) vs. 302 (temporary). Also check out How can I make Chrome stop caching redirects? and the "won't fix" bug.
For completeness, here's the result following the redirect to /Login/Login:
$ echo -e "GET /Login/Login HTTP/1.1\nHost:example.com\n" | openssl s_client -connect example.com:443 \
-ssl3 -ign_eof -CAfile Equifax_Secure_Certificate_Authority.pem
CONNECTED(00000003)
...
Start Time: 1407403671
Timeout : 7200 (sec)
Verify return code: 0 (ok)
read R BLOCK
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 07 Aug 2014 09:27:29 GMT
Content-Length: 1547
<html>
<body>
<form action="/Login/Login" method="post"> <div style="height: 140px">
</div>
<table style="width: 400px; border: 1px solid #058fbe;" cellpadding="5" align="center">
<tr>
<td colspan="2" align="center" style="background-color: #058fbe">
<span style="color: #FFF; font-family: Arial, Helvetica, sans-serif;
font-weight: bold; font-size: 14pt">TERRANET. ZONA ADMINISTRACIÓN</span>
</td>
</tr>
<tr>
<td width="150px">
<img src="/Content/img/login.png" width="150px" />
</td>
<td>
<span style="color: #058fbe; font-family: Arial, Helvetica, sans-serif;
font-weight: bold; font-size: 10pt">usuario</span><br />
<input type="text" style="border: 1px solid #058fbe; width: 190px" name="usuario" /><br />
<span style="color: #058fbe; font-family: Arial, Helvetica, sans-serif;
font-weight: bold; font-size: 10pt">contraseña</span><br />
<input type="password" style="border: 1px solid #058fbe; width: 190px" name="pass" /><br />
<br />
<input type="submit" value="entrar" style="background-color: #058fbe;
width: 80px; color: white; font-family: Arial, Helvetica, sans-serif;
font-weight: bold; font-size: 10pt; border: none" />
</td>
</tr>
</table>
</form>
</body>
</html>
EDIT (August 7, 2014): I see your changes of HTTP/1.1 301 Moved Permanently.
I performed some browsers tests today. I used:
Chrome (Mac Book)
Firefox (Mac Book)
Safari (Mac Book).
Mobile Browser (Android)
Mobile Chrome (iPhone)
Mobile Safari (iPhone)
Explorer (Surface Pro)
Most worked as expected.
Explorer on the Surface Pro tablet hung.
Android's browser (com.android.browser) prompted for a client cert (that's why I am being prompted to set a PIN):
Safari desktop prompted for a client cert:
Do you need client certificates? If so, that's probably the issue. Client side certificates are a mess in browsers.
If you don't need them, then disable them in IIS. See Specify Whether to Use Client Certificates (IIS 7).
This may be because of IP binding as to get it worked properly your HTTPS and HTTP both should bind to same IP address in IIS.
Have you tried restarting your IIS? it may resolve the issue.

Resources