[{"data":1,"prerenderedAt":2605},["ShallowReactive",2],{"navigation_docs_en":3,"-en-usecases-and-demos-oauth2-demo":175,"-en-usecases-and-demos-oauth2-demo-surround":2600},[4,35,64,86,108,135,150],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Quick Start",false,"/en/quick-start","en/1.quick-start",[10,15,20,25,30],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","/en/quick-start/introduction","en/1.quick-start/1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/en/quick-start/installation","en/1.quick-start/2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Getting Started","/en/quick-start/getting-started","en/1.quick-start/3.getting-started","i-lucide-rocket",{"title":26,"path":27,"stem":28,"icon":29},"Docker Desktop Extension","/en/quick-start/docker-desktop-extension","en/1.quick-start/4.docker-desktop-extension","i-simple-icons-docker",{"title":31,"path":32,"stem":33,"icon":34},"CLI","/en/quick-start/cli","en/1.quick-start/5.cli","i-lucide-square-terminal",{"title":36,"path":37,"stem":38,"children":39,"page":6},"Local Environments","/en/local-environments","en/2.local-environments",[40,43,48,52,56,60],{"title":21,"path":41,"stem":42,"icon":24},"/en/local-environments/getting-started","en/2.local-environments/1.getting-started",{"title":44,"path":45,"stem":46,"icon":47},"Colima Kubernetes","/en/local-environments/colima","en/2.local-environments/2.colima","i-simple-icons-kubernetes",{"title":49,"path":50,"stem":51,"icon":29},"Docker Desktop Kubernetes (OSX)","/en/local-environments/docker-desktop-osx","en/2.local-environments/3.docker-desktop-osx",{"title":53,"path":54,"stem":55},"k3d","/en/local-environments/k3d","en/2.local-environments/4.k3d",{"title":57,"path":58,"stem":59},"kind","/en/local-environments/kind","en/2.local-environments/5.kind",{"title":61,"path":62,"stem":63},"minikube","/en/local-environments/minikube","en/2.local-environments/5.minikube",{"title":65,"path":66,"stem":67,"children":68,"page":6},"Shared Environments","/en/shared-environments","en/3.shared-environments",[69,72,76,81],{"title":21,"path":70,"stem":71,"icon":24},"/en/shared-environments/getting-started","en/3.shared-environments/1.getting-started",{"title":73,"path":74,"stem":75,"icon":19},"Installing Gefyra in a Cluster","/en/shared-environments/installation","en/3.shared-environments/2.installation",{"title":77,"path":78,"stem":79,"icon":80},"Managing Gefyra Clients","/en/shared-environments/clients","en/3.shared-environments/3.clients","i-lucide-computer",{"title":82,"path":83,"stem":84,"icon":85},"Connecting to Gefyra","/en/shared-environments/connecting","en/3.shared-environments/4.connecting","i-lucide-link",{"title":87,"path":88,"stem":89,"children":90,"page":6},"Remote K8s","/en/remote-k8s","en/4.remote-k8s",[91,94,99,104],{"title":21,"path":92,"stem":93,"icon":24},"/en/remote-k8s/getting-started","en/4.remote-k8s/1.getting-started",{"title":95,"path":96,"stem":97,"icon":98},"Google Cloud Platform (GCP)","/en/remote-k8s/gcp","en/4.remote-k8s/2.gcp","i-material-icon-theme:gcp",{"title":100,"path":101,"stem":102,"icon":103},"Elastic Kubernetes Service (EKS)","/en/remote-k8s/eks","en/4.remote-k8s/3.eks","i-simple-icons-amazoneks",{"title":105,"path":106,"stem":107,"icon":47},"SysEleven MetaKubde Kubernetes","/en/remote-k8s/sys11","en/4.remote-k8s/4.sys11",{"title":109,"path":110,"stem":111,"children":112,"page":6},"Use Cases and Demos","/en/usecases-and-demos","en/5.usecases-and-demos",[113,116,121,126,130],{"title":21,"path":114,"stem":115,"icon":24},"/en/usecases-and-demos/getting-started","en/5.usecases-and-demos/1.getting-started",{"title":117,"path":118,"stem":119,"icon":120},"Developing Go Applications with Gefyra","/en/usecases-and-demos/golang","en/5.usecases-and-demos/2.golang","i-simple-icons-go",{"title":122,"path":123,"stem":124,"icon":125},"OAuth2 Demo with a Sidecar","/en/usecases-and-demos/oauth2-demo","en/5.usecases-and-demos/3.oauth2-demo","i-devicon-plain:oauth",{"title":127,"path":128,"stem":129,"icon":98},"Remote Development on Google Kubernetes Engine","/en/usecases-and-demos/remote-gke","en/5.usecases-and-demos/4.remote-gke",{"title":131,"path":132,"stem":133,"icon":134},"Run an Ubuntu Container instance","/en/usecases-and-demos/ubuntu-in-namespace","en/5.usecases-and-demos/5.ubuntu-in-namespace","i-simple-icons-ubuntu",{"title":136,"path":137,"stem":138,"children":139,"page":6},"Technical Details","/en/technical-details","en/6.technical-details",[140,145],{"title":141,"path":142,"stem":143,"icon":144},"Architecture","/en/technical-details/architecture","en/6.technical-details/1.architecture","i-lucide-square-chevron-right",{"title":146,"path":147,"stem":148,"icon":149},"What is Gefyra?","/en/technical-details/what-is-gefyra","en/6.technical-details/2.what-is-gefyra","i-lucide-circle-question-mark",{"title":151,"path":152,"stem":153,"children":154,"page":6},"Information","/en/information","en/7.information",[155,160,165,170],{"title":156,"path":157,"stem":158,"icon":159},"Run vs. Bridge","/en/information/run-vs-bridge","en/7.information/1.run-vs-bridge","i-lucide-git-compare-arrows",{"title":161,"path":162,"stem":163,"icon":164},"What changed in Gefyra 2?","/en/information/v1-vs-v2","en/7.information/2.v1-vs-v2","i-lucide-history",{"title":166,"path":167,"stem":168,"icon":169},"Media","/en/information/media","en/7.information/3.media","i-lucide-play",{"title":171,"path":172,"stem":173,"icon":174},"About","/en/information/about","en/7.information/4.about","i-lucide-info",{"id":176,"title":177,"body":178,"description":2593,"extension":2594,"links":2595,"meta":2596,"navigation":2597,"path":123,"seo":2598,"stem":124,"__hash__":2599},"docs_en/en/5.usecases-and-demos/3.oauth2-demo.md","Create a Backend Application with a Sidecar and OAuth2 Authentication",{"type":179,"value":180,"toc":2571},"minimark",[181,185,194,199,230,234,277,280,284,294,297,328,334,341,350,372,376,393,402,409,417,425,428,435,443,446,467,474,508,519,523,528,531,548,573,576,583,620,632,637,788,799,804,995,1004,1095,1099,1115,1349,1367,1529,1535,1570,1576,1580,1583,1590,1597,1600,1604,1628,1862,1865,1869,1879,1883,1894,1975,1978,2028,2038,2042,2052,2080,2083,2092,2103,2110,2117,2125,2128,2132,2146,2235,2238,2278,2282,2285,2292,2299,2302,2309,2316,2322,2326,2333,2439,2449,2486,2489,2492,2497,2501,2508,2512,2518,2545,2548,2552,2567],[182,183,184],"warning",{},"Advanced Usecase",[186,187,188,189,193],"p",{},"This is more of an advanced use-case, if you just want an easy example of how Gefyra works, check out the ",[190,191,192],"a",{"href":41},"getting started guide",".",[195,196,198],"h2",{"id":197},"what-you-will-learn","What you will learn",[200,201,202,206,215,224,227],"ul",{},[203,204,205],"li",{},"Create a (Python-based) backend application that reads a JWT (JSON web token)",[203,207,208,209],{},"Get a local identity provider with ",[190,210,214],{"href":211,"rel":212},"https://www.keycloak.org/",[213],"nofollow","Keycloak",[203,216,217,218,223],{},"Apply the Kubernetes sidecar pattern with ",[190,219,222],{"href":220,"rel":221},"https://oauth2-proxy.github.io/oauth2-proxy/",[213],"OAuth2-Proxy"," and connect the app to Keycloak",[203,225,226],{},"Find and fix a bug",[203,228,229],{},"Start coding locally within the Kubernetes cluster having the sidecar active",[195,231,233],{"id":232},"what-you-will-need","What you will need",[200,235,236,241,254,259,266,274],{},[203,237,238],{},[190,239,240],{"href":17},"Gefyra",[203,242,243,249,250,253],{},[190,244,248],{"href":245,"rel":246,"target":247},"https://github.com/Getdeck/getdeck",[213],"_blank","Getdeck"," for setting up the development infrastructure (runs on ",[251,252,53],"code",{},")",[203,255,256],{},[251,257,258],{},"kubectl",[203,260,261,262],{},"A copy of ",[190,263,264],{"href":264,"rel":265,"target":247},"https://github.com/gefyrahq/gefyra-demos",[213],[203,267,268,269,273],{},"Optionally: ",[190,270,53],{"href":271,"rel":272,"target":247},"https://k3d.io",[213]," or any other preferred Kubernetes cluster",[203,275,276],{},"Optionally: VSCode with Python debugger installed (or any other preferred IDE)",[186,278,279],{},"That's about it. Let's get started.",[195,281,283],{"id":282},"creating-the-development-infrastructure","Creating the Development Infrastructure",[186,285,286,287,193],{},"First, we need a Kubernetes-based development infrastructure which contains all required components. Luckily this can\nbe achieved quite easily with the ",[190,288,290,293],{"href":245,"rel":289,"target":247},[213],[251,291,292],{},"Deck CLI"," from here",[186,295,296],{},"Just run:",[298,299,304],"pre",{"className":300,"code":301,"language":302,"meta":303,"style":303},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","deck get --name oauth2-demo https://github.com/gefyrahq/gefyra-demos.git\n","sh","",[251,305,306],{"__ignoreMap":303},[307,308,311,315,319,322,325],"span",{"class":309,"line":310},"line",1,[307,312,314],{"class":313},"sBMFI","deck",[307,316,318],{"class":317},"sfazB"," get",[307,320,321],{"class":317}," --name",[307,323,324],{"class":317}," oauth2-demo",[307,326,327],{"class":317}," https://github.com/gefyrahq/gefyra-demos.git\n",[186,329,330,331,333],{},"and you will get a fresh ",[251,332,53],{}," cluster running locally with all required components installed.",[186,335,336,340],{},[337,338,339],"strong",{},"Important:"," These workloads are intended for demonstration purposes and are not safe for production deployments.",[186,342,343,346,347,349],{},[337,344,345],{},"Optional:"," If you don't want to create the development infrastructure using ",[251,348,248],{}," you can also provide it\nyourself. You need:",[200,351,352,355,369],{},[203,353,354],{},"a Kubernetes cluster",[203,356,357,358],{},"an identity provider (preferably Keycloak)\n",[200,359,360,363,366],{},[203,361,362],{},"a custom realm with an oauth2 client for the backend service",[203,364,365],{},"a test user with required privileges",[203,367,368],{},"ingress config that supports a full-fledged oauth2 login flow",[203,370,371],{},"the workload manifests for the backend application with the OAuth2-Proxy sidecar",[195,373,375],{"id":374},"getting-the-app-running","Getting the App Running",[186,377,378,380,381,386,387,193,389,392],{},[337,379,345],{}," In order to observe the workload booting up, check out\n",[190,382,385],{"href":383,"rel":384,"target":247},"http://dashboard.127.0.0.1.nip.io:8080/#/workloads?namespace=oauth2-demo",[213],"the Kubernetes dashboard"," coming with this ",[251,388,314],{},[390,391],"br",{},"\nA healthy cluster looks like this:",[186,394,395],{},[396,397],"img",{"alt":398,"className":399,"src":401},"Kubernetes dashboard",[400],"w-full","/img/usecases_oauth2-demo_dashboard1.png",[186,403,404,405,193],{},"Once you have the workload running in Kubernetes, head over to\n",[190,406,407],{"href":407,"rel":408,"target":247},"http://oauth2-demo.127.0.0.1.nip.io:8080/",[213],[186,410,411,412,416],{},"The following page should come up asking you to sign in with ",[413,414,415],"em",{},"OpenID Connect",":",[186,418,419],{},[396,420],{"alt":421,"className":422,"src":424},"OAuth2-Proxy login portal",[423],"mx-auto","/img/usecases_oauth2-demo_oauth2-proxy.png",[186,426,427],{},"Once you click the button you will be redirected to the central login of Keycloak, which looks like this:",[186,429,430],{},[396,431],{"alt":432,"className":433,"src":434},"Keycloak login page",[423],"/img/usecases_oauth2-demo_kc-login.png",[186,436,437,438,193],{},"Please notice how you got redirected to the local domain of Keycloak ",[190,439,442],{"href":440,"rel":441,"target":247},"http://keycloak.127.0.0.1.nip.io:8080/",[213],"http://keycloak.127.0.0.1.nip.io:8080/...",[186,444,445],{},"The demo workload contains a prepared user in Keycloak's database. You can use it to perform a login. The credentials are as\nfollows:",[186,447,448,451,452,458,460,451,463],{},[337,449,450],{},"Username",": ",[413,453,454],{},[190,455,457],{"href":456},"mailto:john@gefyra.dev","john@gefyra.dev",[390,459],{},[337,461,462],{},"Password",[413,464,465],{},[190,466,457],{"href":456},[186,468,469,470,473],{},"Once you hit the ",[413,471,472],{},"Sign In"," button you will be redirected back to the beginning, but this time you will see the json output of\nthe backend service:",[298,475,479],{"className":476,"code":477,"language":478,"meta":303,"style":303},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\"Hello\":\"World\"}\n","json",[251,480,481],{"__ignoreMap":303},[307,482,483,487,490,494,496,498,500,503,505],{"class":309,"line":310},[307,484,486],{"class":485},"sMK4o","{",[307,488,489],{"class":485},"\"",[307,491,493],{"class":492},"spNyl","Hello",[307,495,489],{"class":485},[307,497,416],{"class":485},[307,499,489],{"class":485},[307,501,502],{"class":317},"World",[307,504,489],{"class":485},[307,506,507],{"class":485},"}\n",[186,509,510,511,515,516,518],{},"Voilà, we have a full-fledged ",[190,512,415],{"href":513,"rel":514,"target":247},"https://openid.net/connect/",[213]," login flow running in a Kubernetes cluster.",[390,517],{},"\nSo are we done yet? Not quite. Let's move on to the internals.",[195,520,522],{"id":521},"the-scheme-of-the-infrastructure","The Scheme of the Infrastructure",[524,525,527],"h3",{"id":526},"kubernetes-overview","Kubernetes Overview",[186,529,530],{},"The Kubernetes cluster is running three important components for this use case:",[200,532,533,536,539],{},[203,534,535],{},"Keycloak: the identity provider compatible with OpenID Connect (OIDC)",[203,537,538],{},"OAuth2-Proxy: a reverse proxy compatible with OpenID Connect",[203,540,541,542,547],{},"Backend Application: a ",[190,543,546],{"href":544,"rel":545,"target":247},"https://fastapi.tiangolo.com/",[213],"FastAPI"," application",[186,549,550,551,558,559,564,565,568,569,572],{},"The OAuth2-Proxy is implemented as a sidecar and runs side-by-side in each ",[190,552,555],{"href":553,"rel":554,"target":247},"https://kubernetes.io/docs/concepts/workloads/pods/",[213],[413,556,557],{},"Pod"," with the backend application. If you are\nnot yet familiar with the sidecar pattern ",[190,560,563],{"href":561,"rel":562,"target":247},"https://www.oreilly.com/library/view/designing-distributed-systems/9781491983638/ch02.html",[213],"please check out this resource",".\nKeycloak runs in a ",[413,566,567],{},"StatefulSet"," and is connected to a ",[413,570,571],{},"PostgreSQL"," database.",[186,574,575],{},"The Kubernetes objects of the workload are as follows:",[186,577,578],{},[396,579],{"alt":580,"className":581,"src":582},"Kubernetes object relation",[400],"/img/usecases_oauth2-demo-k8s1.png",[186,584,585,586,593,594,601,602,605,606,608,609,614,615,193],{},"In this picture you can find two ",[190,587,590],{"href":588,"rel":589,"target":247},"https://kubernetes.io/docs/concepts/services-networking/ingress/",[213],[413,591,592],{},"Ingresses","\ndefinitions: one is serving the application ",[190,595,598],{"href":596,"rel":597,"target":247},"https://kubernetes.io/docs/concepts/workloads/controllers/deployment/",[213],[413,599,600],{},"Deployment"," ",[413,603,604],{},"oauth2-demo","\nwhich schedules one ",[413,607,557],{}," under ",[190,610,613],{"href":611,"rel":612,"target":247},"http://oauth2-demo.127.0.0.1.nip.io:8080",[213],"oauth2-demo.127.0.0.1.nip.io:8080",", the other is\nserving Keycloak under ",[190,616,619],{"href":617,"rel":618,"target":247},"http://keycloak.127.0.0.1.nip.io:8080",[213],"keycloak.127.0.0.1.nip.io:8080",[186,621,622,624,625,628,629,193],{},[337,623,339],{}," Please mind that port ",[413,626,627],{},"8080"," is a port mapping. From within the cluster you will see it running on port ",[413,630,631],{},"80",[186,633,634,635,416],{},"You can introspect the Ingress also with ",[251,636,258],{},[298,638,640],{"className":300,"code":639,"language":302,"meta":303,"style":303},"> kubectl --namespace oauth2-demo get ingress \n\nNAME                             CLASS    HOSTS                          ADDRESS      PORTS     AGE\nkeycloak                         \u003Cnone>   keycloak.127.0.0.1.nip.io      172.23.0.2   80, 443   56m\nkeycloak-console                 \u003Cnone>   keycloak.127.0.0.1.nip.io      172.23.0.2   80, 443   56m\noauth2-demo                      \u003Cnone>   oauth2-demo.127.0.0.1.nip.io   172.23.0.2   80        56m\ndashboard-kubernetes-dashboard   \u003Cnone>   dashboard.127.0.0.1.nip.io     172.23.0.2   80        56m\n",[251,641,642,651,658,679,712,737,763],{"__ignoreMap":303},[307,643,644,647],{"class":309,"line":310},[307,645,646],{"class":485},">",[307,648,650],{"class":649},"sTEyZ"," kubectl --namespace oauth2-demo get ingress \n",[307,652,654],{"class":309,"line":653},2,[307,655,657],{"emptyLinePlaceholder":656},true,"\n",[307,659,661,664,667,670,673,676],{"class":309,"line":660},3,[307,662,663],{"class":313},"NAME",[307,665,666],{"class":317},"                             CLASS",[307,668,669],{"class":317},"    HOSTS",[307,671,672],{"class":317},"                          ADDRESS",[307,674,675],{"class":317},"      PORTS",[307,677,678],{"class":317},"     AGE\n",[307,680,682,685,688,691,694,696,699,703,706,709],{"class":309,"line":681},4,[307,683,684],{"class":313},"keycloak",[307,686,687],{"class":485},"                         \u003C",[307,689,690],{"class":317},"non",[307,692,693],{"class":649},"e",[307,695,646],{"class":485},[307,697,698],{"class":317},"   keycloak.127.0.0.1.nip.io",[307,700,702],{"class":701},"sbssI","      172.23.0.2",[307,704,705],{"class":317},"   80,",[307,707,708],{"class":701}," 443",[307,710,711],{"class":317},"   56m\n",[307,713,715,718,721,723,725,727,729,731,733,735],{"class":309,"line":714},5,[307,716,717],{"class":313},"keycloak-console",[307,719,720],{"class":485},"                 \u003C",[307,722,690],{"class":317},[307,724,693],{"class":649},[307,726,646],{"class":485},[307,728,698],{"class":317},[307,730,702],{"class":701},[307,732,705],{"class":317},[307,734,708],{"class":701},[307,736,711],{"class":317},[307,738,740,742,745,747,749,751,754,757,760],{"class":309,"line":739},6,[307,741,604],{"class":313},[307,743,744],{"class":485},"                      \u003C",[307,746,690],{"class":317},[307,748,693],{"class":649},[307,750,646],{"class":485},[307,752,753],{"class":317},"   oauth2-demo.127.0.0.1.nip.io",[307,755,756],{"class":701},"   172.23.0.2",[307,758,759],{"class":701},"   80",[307,761,762],{"class":317},"        56m\n",[307,764,766,769,772,774,776,778,781,784,786],{"class":309,"line":765},7,[307,767,768],{"class":313},"dashboard-kubernetes-dashboard",[307,770,771],{"class":485},"   \u003C",[307,773,690],{"class":317},[307,775,693],{"class":649},[307,777,646],{"class":485},[307,779,780],{"class":317},"   dashboard.127.0.0.1.nip.io",[307,782,783],{"class":701},"     172.23.0.2",[307,785,759],{"class":701},[307,787,762],{"class":317},[186,789,790,791,798],{},"The next layer adds the Kubernetes ",[190,792,795],{"href":793,"rel":794,"target":247},"https://kubernetes.io/docs/concepts/services-networking/service/",[213],[413,796,797],{},"Service"," objects which are\nrequired to access a Pod.",[186,800,801,802,416],{},"You can introspect the Services also with ",[251,803,258],{},[298,805,807],{"className":300,"code":806,"language":302,"meta":303,"style":303},"> kubectl --namespace oauth2-demo get service\n\nNAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                    AGE\nkeycloak-http                    ClusterIP   10.43.40.200    \u003Cnone>        80/TCP,8443/TCP,9990/TCP   62m\nkeycloak-headless                ClusterIP   None            \u003Cnone>        80/TCP                     62m\nkeycloak-postgresql              ClusterIP   10.43.231.210   \u003Cnone>        5432/TCP                   62m\nkeycloak-postgresql-headless     ClusterIP   None            \u003Cnone>        5432/TCP                   62m\noauth2-demo                      ClusterIP   10.43.160.68    \u003Cnone>        8080/TCP                   62m\ndashboard-kubernetes-dashboard   ClusterIP   10.43.159.219   \u003Cnone>        61348/TCP                  62m\n",[251,808,809,816,820,847,873,899,924,946,970],{"__ignoreMap":303},[307,810,811,813],{"class":309,"line":310},[307,812,646],{"class":485},[307,814,815],{"class":649}," kubectl --namespace oauth2-demo get service\n",[307,817,818],{"class":309,"line":653},[307,819,657],{"emptyLinePlaceholder":656},[307,821,822,824,827,830,833,836,839,842,844],{"class":309,"line":660},[307,823,663],{"class":313},[307,825,826],{"class":317},"                             TYPE",[307,828,829],{"class":317},"        CLUSTER-IP",[307,831,832],{"class":317},"      EXTERNAL-IP",[307,834,835],{"class":317},"   PORT",[307,837,838],{"class":485},"(",[307,840,841],{"class":313},"S",[307,843,253],{"class":485},[307,845,846],{"class":317},"                    AGE\n",[307,848,849,852,855,858,861,863,865,867,870],{"class":309,"line":681},[307,850,851],{"class":313},"keycloak-http",[307,853,854],{"class":317},"                    ClusterIP",[307,856,857],{"class":701},"   10.43.40.200",[307,859,860],{"class":485},"    \u003C",[307,862,690],{"class":317},[307,864,693],{"class":649},[307,866,646],{"class":485},[307,868,869],{"class":317},"        80/TCP,8443/TCP,9990/TCP",[307,871,872],{"class":317},"   62m\n",[307,874,875,878,881,884,887,889,891,893,896],{"class":309,"line":714},[307,876,877],{"class":313},"keycloak-headless",[307,879,880],{"class":317},"                ClusterIP",[307,882,883],{"class":317},"   None",[307,885,886],{"class":485},"            \u003C",[307,888,690],{"class":317},[307,890,693],{"class":649},[307,892,646],{"class":485},[307,894,895],{"class":317},"        80/TCP",[307,897,898],{"class":317},"                     62m\n",[307,900,901,904,907,910,912,914,916,918,921],{"class":309,"line":739},[307,902,903],{"class":313},"keycloak-postgresql",[307,905,906],{"class":317},"              ClusterIP",[307,908,909],{"class":701},"   10.43.231.210",[307,911,771],{"class":485},[307,913,690],{"class":317},[307,915,693],{"class":649},[307,917,646],{"class":485},[307,919,920],{"class":317},"        5432/TCP",[307,922,923],{"class":317},"                   62m\n",[307,925,926,929,932,934,936,938,940,942,944],{"class":309,"line":765},[307,927,928],{"class":313},"keycloak-postgresql-headless",[307,930,931],{"class":317},"     ClusterIP",[307,933,883],{"class":317},[307,935,886],{"class":485},[307,937,690],{"class":317},[307,939,693],{"class":649},[307,941,646],{"class":485},[307,943,920],{"class":317},[307,945,923],{"class":317},[307,947,949,951,954,957,959,961,963,965,968],{"class":309,"line":948},8,[307,950,604],{"class":313},[307,952,953],{"class":317},"                      ClusterIP",[307,955,956],{"class":701},"   10.43.160.68",[307,958,860],{"class":485},[307,960,690],{"class":317},[307,962,693],{"class":649},[307,964,646],{"class":485},[307,966,967],{"class":317},"        8080/TCP",[307,969,923],{"class":317},[307,971,973,975,978,981,983,985,987,989,992],{"class":309,"line":972},9,[307,974,768],{"class":313},[307,976,977],{"class":317},"   ClusterIP",[307,979,980],{"class":701},"   10.43.159.219",[307,982,771],{"class":485},[307,984,690],{"class":317},[307,986,693],{"class":649},[307,988,646],{"class":485},[307,990,991],{"class":317},"        61348/TCP",[307,993,994],{"class":317},"                  62m\n",[186,996,997,998,1000,1001,1003],{},"Please ignore the other services as they are not important for this example.",[390,999],{},"\nFinally, please also check out the Pods in the cluster's namespace with ",[251,1002,258],{},". It should be similar to:",[298,1005,1007],{"className":300,"code":1006,"language":302,"meta":303,"style":303},"> kubectl --namespace oauth2-demo get pod\n\nNAME                                              READY   STATUS    RESTARTS   AGE\noauth2-demo-675f5c55b5-xxj57                      2/2     Running   0          63m\ndashboard-kubernetes-dashboard-65dbdd8978-gd9jt   1/1     Running   0          63m\nkeycloak-postgresql-0                             1/1     Running   0          63m\nkeycloak-0                                        1/1     Running   0          63m\n\n",[251,1008,1009,1016,1020,1036,1053,1067,1081],{"__ignoreMap":303},[307,1010,1011,1013],{"class":309,"line":310},[307,1012,646],{"class":485},[307,1014,1015],{"class":649}," kubectl --namespace oauth2-demo get pod\n",[307,1017,1018],{"class":309,"line":653},[307,1019,657],{"emptyLinePlaceholder":656},[307,1021,1022,1024,1027,1030,1033],{"class":309,"line":660},[307,1023,663],{"class":313},[307,1025,1026],{"class":317},"                                              READY",[307,1028,1029],{"class":317},"   STATUS",[307,1031,1032],{"class":317},"    RESTARTS",[307,1034,1035],{"class":317},"   AGE\n",[307,1037,1038,1041,1044,1047,1050],{"class":309,"line":681},[307,1039,1040],{"class":313},"oauth2-demo-675f5c55b5-xxj57",[307,1042,1043],{"class":317},"                      2/2",[307,1045,1046],{"class":317},"     Running",[307,1048,1049],{"class":701},"   0",[307,1051,1052],{"class":317},"          63m\n",[307,1054,1055,1058,1061,1063,1065],{"class":309,"line":714},[307,1056,1057],{"class":313},"dashboard-kubernetes-dashboard-65dbdd8978-gd9jt",[307,1059,1060],{"class":317},"   1/1",[307,1062,1046],{"class":317},[307,1064,1049],{"class":701},[307,1066,1052],{"class":317},[307,1068,1069,1072,1075,1077,1079],{"class":309,"line":739},[307,1070,1071],{"class":313},"keycloak-postgresql-0",[307,1073,1074],{"class":317},"                             1/1",[307,1076,1046],{"class":317},[307,1078,1049],{"class":701},[307,1080,1052],{"class":317},[307,1082,1083,1086,1089,1091,1093],{"class":309,"line":765},[307,1084,1085],{"class":313},"keycloak-0",[307,1087,1088],{"class":317},"                                        1/1",[307,1090,1046],{"class":317},[307,1092,1049],{"class":701},[307,1094,1052],{"class":317},[524,1096,1098],{"id":1097},"the-oauth2-demo-sidecar-workload","The OAuth2-Demo Sidecar Workload",[186,1100,1101,1102,1107,1108,1111,1112,416],{},"If you want to know more about the implementation of the sidecar pattern in this example please head over to the\n",[190,1103,1106],{"href":1104,"rel":1105,"target":247},"https://github.com/gefyrahq/gefyra-demos/blob/main/oauth2-demo/oauth2-demo.yaml#L37",[213],"workload manifest",".\nThe important part is that the Pod template specifies two containers. The first is ",[413,1109,1110],{},"name: oauth2-proxy"," and the second is\n",[413,1113,1114],{},"name: oauth2-demo-app",[298,1116,1120],{"className":1117,"code":1118,"language":1119,"meta":303,"style":303},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[...]\ncontainers:\n- name: oauth2-proxy\n  image: quay.io/oauth2-proxy/oauth2-proxy:v7.2.1\n  imagePullPolicy: IfNotPresent\n  [...]\n  ports:\n    - containerPort: 8809\n      protocol: TCP\n      name: http\n  envFrom:\n    - configMapRef:\n        name: oauth2-oauth2proxy\n- name: oauth2-demo-app\n  [...]\n  image: \"quay.io/gefyra/oauth2-demo:latest\"\n  imagePullPolicy: Always\n  ports:\n    - name: http-intern\n      containerPort: 8155\n      protocol: TCP\n[...]\n","yaml",[251,1121,1122,1133,1142,1155,1165,1175,1184,1191,1204,1214,1225,1233,1243,1254,1266,1275,1291,1301,1308,1320,1331,1340],{"__ignoreMap":303},[307,1123,1124,1127,1130],{"class":309,"line":310},[307,1125,1126],{"class":485},"[",[307,1128,1129],{"class":701},"...",[307,1131,1132],{"class":485},"]\n",[307,1134,1135,1139],{"class":309,"line":653},[307,1136,1138],{"class":1137},"swJcz","containers",[307,1140,1141],{"class":485},":\n",[307,1143,1144,1147,1150,1152],{"class":309,"line":660},[307,1145,1146],{"class":485},"-",[307,1148,1149],{"class":1137}," name",[307,1151,416],{"class":485},[307,1153,1154],{"class":317}," oauth2-proxy\n",[307,1156,1157,1160,1162],{"class":309,"line":681},[307,1158,1159],{"class":1137},"  image",[307,1161,416],{"class":485},[307,1163,1164],{"class":317}," quay.io/oauth2-proxy/oauth2-proxy:v7.2.1\n",[307,1166,1167,1170,1172],{"class":309,"line":714},[307,1168,1169],{"class":1137},"  imagePullPolicy",[307,1171,416],{"class":485},[307,1173,1174],{"class":317}," IfNotPresent\n",[307,1176,1177,1180,1182],{"class":309,"line":739},[307,1178,1179],{"class":485},"  [",[307,1181,1129],{"class":701},[307,1183,1132],{"class":485},[307,1185,1186,1189],{"class":309,"line":765},[307,1187,1188],{"class":1137},"  ports",[307,1190,1141],{"class":485},[307,1192,1193,1196,1199,1201],{"class":309,"line":948},[307,1194,1195],{"class":485},"    -",[307,1197,1198],{"class":1137}," containerPort",[307,1200,416],{"class":485},[307,1202,1203],{"class":701}," 8809\n",[307,1205,1206,1209,1211],{"class":309,"line":972},[307,1207,1208],{"class":1137},"      protocol",[307,1210,416],{"class":485},[307,1212,1213],{"class":317}," TCP\n",[307,1215,1217,1220,1222],{"class":309,"line":1216},10,[307,1218,1219],{"class":1137},"      name",[307,1221,416],{"class":485},[307,1223,1224],{"class":317}," http\n",[307,1226,1228,1231],{"class":309,"line":1227},11,[307,1229,1230],{"class":1137},"  envFrom",[307,1232,1141],{"class":485},[307,1234,1236,1238,1241],{"class":309,"line":1235},12,[307,1237,1195],{"class":485},[307,1239,1240],{"class":1137}," configMapRef",[307,1242,1141],{"class":485},[307,1244,1246,1249,1251],{"class":309,"line":1245},13,[307,1247,1248],{"class":1137},"        name",[307,1250,416],{"class":485},[307,1252,1253],{"class":317}," oauth2-oauth2proxy\n",[307,1255,1257,1259,1261,1263],{"class":309,"line":1256},14,[307,1258,1146],{"class":485},[307,1260,1149],{"class":1137},[307,1262,416],{"class":485},[307,1264,1265],{"class":317}," oauth2-demo-app\n",[307,1267,1269,1271,1273],{"class":309,"line":1268},15,[307,1270,1179],{"class":485},[307,1272,1129],{"class":701},[307,1274,1132],{"class":485},[307,1276,1278,1280,1282,1285,1288],{"class":309,"line":1277},16,[307,1279,1159],{"class":1137},[307,1281,416],{"class":485},[307,1283,1284],{"class":485}," \"",[307,1286,1287],{"class":317},"quay.io/gefyra/oauth2-demo:latest",[307,1289,1290],{"class":485},"\"\n",[307,1292,1294,1296,1298],{"class":309,"line":1293},17,[307,1295,1169],{"class":1137},[307,1297,416],{"class":485},[307,1299,1300],{"class":317}," Always\n",[307,1302,1304,1306],{"class":309,"line":1303},18,[307,1305,1188],{"class":1137},[307,1307,1141],{"class":485},[307,1309,1311,1313,1315,1317],{"class":309,"line":1310},19,[307,1312,1195],{"class":485},[307,1314,1149],{"class":1137},[307,1316,416],{"class":485},[307,1318,1319],{"class":317}," http-intern\n",[307,1321,1323,1326,1328],{"class":309,"line":1322},20,[307,1324,1325],{"class":1137},"      containerPort",[307,1327,416],{"class":485},[307,1329,1330],{"class":701}," 8155\n",[307,1332,1334,1336,1338],{"class":309,"line":1333},21,[307,1335,1208],{"class":1137},[307,1337,416],{"class":485},[307,1339,1213],{"class":317},[307,1341,1343,1345,1347],{"class":309,"line":1342},22,[307,1344,1126],{"class":485},[307,1346,1129],{"class":701},[307,1348,1132],{"class":485},[186,1350,1351,1352,1355,1356,1359,1360,1363,1364,1366],{},"Please have a closer look at the port configuration. The oauth2-proxy runs on port ",[413,1353,1354],{},"8809"," (with name ",[413,1357,1358],{},"http",") and oauth2-demo-app\nruns on port ",[413,1361,1362],{},"8155",". You can describe the associated service with ",[251,1365,258],{}," to see which of both ports the traffic is pointed to:",[298,1368,1370],{"className":300,"code":1369,"language":302,"meta":303,"style":303},"> kubectl -n oauth2-demo describe service oauth2-demo\n\nName:              oauth2-demo\nNamespace:         oauth2-demo\nLabels:            app.kubernetes.io/instance=gefyra-demos\n                   app.kubernetes.io/name=oauth2-demo\nAnnotations:       \u003Cnone>\nSelector:          app.kubernetes.io/instance=gefyra-demos,app.kubernetes.io/name=oauth2-demo\nType:              ClusterIP\nIP Families:       \u003Cnone>\nIP:                10.43.160.68\nIPs:               10.43.160.68\nPort:              http  8080/TCP\nTargetPort:        http/TCP\nEndpoints:         10.42.1.4:8809\nSession Affinity:  None\nEvents:            \u003Cnone>\n\n",[251,1371,1372,1379,1383,1391,1399,1407,1415,1430,1438,1446,1462,1470,1478,1489,1497,1505,1516],{"__ignoreMap":303},[307,1373,1374,1376],{"class":309,"line":310},[307,1375,646],{"class":485},[307,1377,1378],{"class":649}," kubectl -n oauth2-demo describe service oauth2-demo\n",[307,1380,1381],{"class":309,"line":653},[307,1382,657],{"emptyLinePlaceholder":656},[307,1384,1385,1388],{"class":309,"line":660},[307,1386,1387],{"class":313},"Name:",[307,1389,1390],{"class":317},"              oauth2-demo\n",[307,1392,1393,1396],{"class":309,"line":681},[307,1394,1395],{"class":313},"Namespace:",[307,1397,1398],{"class":317},"         oauth2-demo\n",[307,1400,1401,1404],{"class":309,"line":714},[307,1402,1403],{"class":313},"Labels:",[307,1405,1406],{"class":317},"            app.kubernetes.io/instance=gefyra-demos\n",[307,1408,1409,1412],{"class":309,"line":739},[307,1410,1411],{"class":313},"                   app.kubernetes.io/name",[307,1413,1414],{"class":317},"=oauth2-demo\n",[307,1416,1417,1420,1423,1425,1427],{"class":309,"line":765},[307,1418,1419],{"class":313},"Annotations:",[307,1421,1422],{"class":485},"       \u003C",[307,1424,690],{"class":317},[307,1426,693],{"class":649},[307,1428,1429],{"class":485},">\n",[307,1431,1432,1435],{"class":309,"line":948},[307,1433,1434],{"class":313},"Selector:",[307,1436,1437],{"class":317},"          app.kubernetes.io/instance=gefyra-demos,app.kubernetes.io/name=oauth2-demo\n",[307,1439,1440,1443],{"class":309,"line":972},[307,1441,1442],{"class":313},"Type:",[307,1444,1445],{"class":317},"              ClusterIP\n",[307,1447,1448,1451,1454,1456,1458,1460],{"class":309,"line":1216},[307,1449,1450],{"class":313},"IP",[307,1452,1453],{"class":317}," Families:",[307,1455,1422],{"class":485},[307,1457,690],{"class":317},[307,1459,693],{"class":649},[307,1461,1429],{"class":485},[307,1463,1464,1467],{"class":309,"line":1227},[307,1465,1466],{"class":313},"IP:",[307,1468,1469],{"class":701},"                10.43.160.68\n",[307,1471,1472,1475],{"class":309,"line":1235},[307,1473,1474],{"class":313},"IPs:",[307,1476,1477],{"class":701},"               10.43.160.68\n",[307,1479,1480,1483,1486],{"class":309,"line":1245},[307,1481,1482],{"class":313},"Port:",[307,1484,1485],{"class":317},"              http",[307,1487,1488],{"class":317},"  8080/TCP\n",[307,1490,1491,1494],{"class":309,"line":1256},[307,1492,1493],{"class":313},"TargetPort:",[307,1495,1496],{"class":317},"        http/TCP\n",[307,1498,1499,1502],{"class":309,"line":1268},[307,1500,1501],{"class":313},"Endpoints:",[307,1503,1504],{"class":317},"         10.42.1.4:8809\n",[307,1506,1507,1510,1513],{"class":309,"line":1277},[307,1508,1509],{"class":313},"Session",[307,1511,1512],{"class":317}," Affinity:",[307,1514,1515],{"class":317},"  None\n",[307,1517,1518,1521,1523,1525,1527],{"class":309,"line":1293},[307,1519,1520],{"class":313},"Events:",[307,1522,886],{"class":485},[307,1524,690],{"class":317},[307,1526,693],{"class":649},[307,1528,1429],{"class":485},[186,1530,1531,1532,1534],{},"For the sidecar pattern to function, the service speaks to the target Pod on port ",[413,1533,1354],{}," which is served by the oauth2-proxy.\nA closer review of oauth2-proxy's configuration reveals to which address the proxy upstreams all requests:",[298,1536,1538],{"className":1117,"code":1537,"language":1119,"meta":303,"style":303},"[...]\nOAUTH2_PROXY_UPSTREAMS: \"http://127.0.0.1:8155\"\n[...]\n",[251,1539,1540,1548,1562],{"__ignoreMap":303},[307,1541,1542,1544,1546],{"class":309,"line":310},[307,1543,1126],{"class":485},[307,1545,1129],{"class":701},[307,1547,1132],{"class":485},[307,1549,1550,1553,1555,1557,1560],{"class":309,"line":653},[307,1551,1552],{"class":1137},"OAUTH2_PROXY_UPSTREAMS",[307,1554,416],{"class":485},[307,1556,1284],{"class":485},[307,1558,1559],{"class":317},"http://127.0.0.1:8155",[307,1561,1290],{"class":485},[307,1563,1564,1566,1568],{"class":309,"line":660},[307,1565,1126],{"class":485},[307,1567,1129],{"class":701},[307,1569,1132],{"class":485},[186,1571,1572,1573,193],{},"This is precisely the connection to the backend application ",[337,1574,1575],{},"in each Pod",[524,1577,1579],{"id":1578},"the-openid-connect-flow-in-brief","The OpenID Connect Flow in Brief",[186,1581,1582],{},"The following image depicts the OpenID Connect flow in brief how it is working in this example:",[186,1584,1585],{},[396,1586],{"alt":1587,"className":1588,"src":1589},"The OIDC flow in brief",[400],"/img/usecases_oauth2-demo-oidc.png",[186,1591,1592,1593,1596],{},"As you can see, the OAuth2-Proxy only passes authenticated traffic to the backend application. That breaks\nthe application free from (potentially unsafe) custom OIDC code and authorization handling. ",[337,1594,1595],{},"This is standard procedure\nand should not be part of your code",". Make use of this pattern when having this requirement.",[186,1598,1599],{},"Ok! Enough for the workload internals. Let's check out how Gefyra helps out with fixing nasty bugs.",[195,1601,1603],{"id":1602},"the-example-bug","The Example Bug",[186,1605,1606,1607,1611,1612,1615,1616,1619,1620,1623,1624],{},"If you hit the troublesome route ",[190,1608,1609],{"href":1609,"rel":1610,"target":247},"http://oauth2-demo.127.0.0.1.nip.io:8080/items/123",[213],"\n(with ",[413,1613,1614],{},"123"," as an example for any int value) you will face the ",[251,1617,1618],{},"Internal Server Error"," message. That is a ",[413,1621,1622],{},"HTTP 500"," status.\nThe code being executed can be found\nhere: ",[190,1625,1626],{"href":1626,"rel":1627,"target":247},"https://github.com/gefyrahq/gefyra-demos/blob/main/oauth2-demo/app/main.py#L23",[213],[298,1629,1633],{"className":1630,"code":1631,"language":1632,"meta":303,"style":303},"language-py shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","@app.get(\"/items/{item_id}\")\nasync def get_item(item_id: int, x_forwarded_access_token: Optional[str] = Header(None)):\n    if x_forwarded_access_token:\n        data = jwt.decode(x_forwarded_access_token, options={\"verify_signature\": False})\n        mail = data[\"Email\"]\n        return {\"item_id\": item_id, \"Email\": mail}\n    else:\n        return {\"item_id\": item_id, \"Email\": \"not given\"}\n","py",[251,1634,1635,1664,1714,1724,1765,1786,1820,1827],{"__ignoreMap":303},[307,1636,1637,1640,1644,1646,1649,1651,1653,1656,1659,1661],{"class":309,"line":310},[307,1638,1639],{"class":485},"@",[307,1641,1643],{"class":1642},"s2Zo4","app",[307,1645,193],{"class":485},[307,1647,1648],{"class":1642},"get",[307,1650,838],{"class":485},[307,1652,489],{"class":485},[307,1654,1655],{"class":317},"/items/",[307,1657,1658],{"class":701},"{item_id}",[307,1660,489],{"class":485},[307,1662,1663],{"class":485},")\n",[307,1665,1666,1669,1672,1675,1677,1681,1683,1686,1689,1692,1694,1697,1699,1702,1705,1708,1711],{"class":309,"line":653},[307,1667,1668],{"class":492},"async",[307,1670,1671],{"class":492}," def",[307,1673,1674],{"class":1642}," get_item",[307,1676,838],{"class":485},[307,1678,1680],{"class":1679},"sHdIc","item_id",[307,1682,416],{"class":485},[307,1684,1685],{"class":313}," int",[307,1687,1688],{"class":485},",",[307,1690,1691],{"class":1679}," x_forwarded_access_token",[307,1693,416],{"class":485},[307,1695,1696],{"class":649}," Optional",[307,1698,1126],{"class":485},[307,1700,1701],{"class":313},"str",[307,1703,1704],{"class":485},"]",[307,1706,1707],{"class":485}," =",[307,1709,1710],{"class":1642}," Header",[307,1712,1713],{"class":485},"(None)):\n",[307,1715,1716,1720,1722],{"class":309,"line":660},[307,1717,1719],{"class":1718},"s7zQu","    if",[307,1721,1691],{"class":649},[307,1723,1141],{"class":485},[307,1725,1726,1729,1732,1735,1737,1740,1742,1745,1747,1750,1753,1755,1758,1760,1762],{"class":309,"line":681},[307,1727,1728],{"class":649},"        data ",[307,1730,1731],{"class":485},"=",[307,1733,1734],{"class":649}," jwt",[307,1736,193],{"class":485},[307,1738,1739],{"class":1642},"decode",[307,1741,838],{"class":485},[307,1743,1744],{"class":1642},"x_forwarded_access_token",[307,1746,1688],{"class":485},[307,1748,1749],{"class":1679}," options",[307,1751,1752],{"class":485},"={",[307,1754,489],{"class":485},[307,1756,1757],{"class":317},"verify_signature",[307,1759,489],{"class":485},[307,1761,416],{"class":485},[307,1763,1764],{"class":485}," False})\n",[307,1766,1767,1770,1772,1775,1777,1779,1782,1784],{"class":309,"line":714},[307,1768,1769],{"class":649},"        mail ",[307,1771,1731],{"class":485},[307,1773,1774],{"class":649}," data",[307,1776,1126],{"class":485},[307,1778,489],{"class":485},[307,1780,1781],{"class":317},"Email",[307,1783,489],{"class":485},[307,1785,1132],{"class":485},[307,1787,1788,1791,1794,1796,1798,1800,1802,1805,1807,1809,1811,1813,1815,1818],{"class":309,"line":739},[307,1789,1790],{"class":1718},"        return",[307,1792,1793],{"class":485}," {",[307,1795,489],{"class":485},[307,1797,1680],{"class":317},[307,1799,489],{"class":485},[307,1801,416],{"class":485},[307,1803,1804],{"class":649}," item_id",[307,1806,1688],{"class":485},[307,1808,1284],{"class":485},[307,1810,1781],{"class":317},[307,1812,489],{"class":485},[307,1814,416],{"class":485},[307,1816,1817],{"class":649}," mail",[307,1819,507],{"class":485},[307,1821,1822,1825],{"class":309,"line":765},[307,1823,1824],{"class":1718},"    else",[307,1826,1141],{"class":485},[307,1828,1829,1831,1833,1835,1837,1839,1841,1843,1845,1847,1849,1851,1853,1855,1858,1860],{"class":309,"line":948},[307,1830,1790],{"class":1718},[307,1832,1793],{"class":485},[307,1834,489],{"class":485},[307,1836,1680],{"class":317},[307,1838,489],{"class":485},[307,1840,416],{"class":485},[307,1842,1804],{"class":649},[307,1844,1688],{"class":485},[307,1846,1284],{"class":485},[307,1848,1781],{"class":317},[307,1850,489],{"class":485},[307,1852,416],{"class":485},[307,1854,1284],{"class":485},[307,1856,1857],{"class":317},"not given",[307,1859,489],{"class":485},[307,1861,507],{"class":485},[186,1863,1864],{},"Of course, you are a very attentive reader and found the mistake immediately, but let's move on for the sake of this example.",[195,1866,1868],{"id":1867},"gefyra-to-the-rescue","Gefyra to the Rescue",[186,1870,1871,1872,1875,1876,1878],{},"As always, the first would be to spin up Gefyra with\n",[251,1873,1874],{},"gefyra up",". Please be sure to still have the development cluster active in your current ",[251,1877,258],{}," context.",[524,1880,1882],{"id":1881},"running-a-development-instance-of-the-container","Running a Development Instance of the Container",[186,1884,1885,1886,1889,1890,1893],{},"In order to inspect the application and pinpoint the bug, it requires a local instance of the container. Ideally with a\ndebug server running. Since you need the sidecar in place (for the OIDC logic), the development instance must be placed\nin a Pod with the sidecar pattern. Gefyra offers you a unique mechanism to achieve exactly that.\nStart the development instance like so (set ",[251,1887,1888],{},"LOCAL_DIR"," to the directory where you've copied/cloned ",[251,1891,1892],{},"gefyra-demos"," to):",[298,1895,1897],{"className":300,"code":1896,"language":302,"meta":303,"style":303},"export LOCAL_DIR=/home/\u003C...>/gefyra-demos/oauth2-demo/app\ngefyra run -i quay.io/gefyra/oauth2-demo -N myfastapi-demo \\\n    -n oauth2-demo -v $LOCAL_DIR:/app \\\n    -c \"bash -c 'python -m debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn main:app --host 0.0.0.0 --port 8155 --reload'\"\n",[251,1898,1899,1922,1945,1963],{"__ignoreMap":303},[307,1900,1901,1904,1907,1909,1912,1915,1917,1919],{"class":309,"line":310},[307,1902,1903],{"class":492},"export",[307,1905,1906],{"class":649}," LOCAL_DIR",[307,1908,1731],{"class":485},[307,1910,1911],{"class":649},"/home/",[307,1913,1914],{"class":485},"\u003C",[307,1916,1129],{"class":649},[307,1918,646],{"class":485},[307,1920,1921],{"class":649},"/gefyra-demos/oauth2-demo/app\n",[307,1923,1924,1927,1930,1933,1936,1939,1942],{"class":309,"line":653},[307,1925,1926],{"class":313},"gefyra",[307,1928,1929],{"class":317}," run",[307,1931,1932],{"class":317}," -i",[307,1934,1935],{"class":317}," quay.io/gefyra/oauth2-demo",[307,1937,1938],{"class":317}," -N",[307,1940,1941],{"class":317}," myfastapi-demo",[307,1943,1944],{"class":649}," \\\n",[307,1946,1947,1950,1952,1955,1958,1961],{"class":309,"line":660},[307,1948,1949],{"class":317},"    -n",[307,1951,324],{"class":317},[307,1953,1954],{"class":317}," -v",[307,1956,1957],{"class":649}," $LOCAL_DIR",[307,1959,1960],{"class":317},":/app",[307,1962,1944],{"class":649},[307,1964,1965,1968,1970,1973],{"class":309,"line":681},[307,1966,1967],{"class":317},"    -c",[307,1969,1284],{"class":485},[307,1971,1972],{"class":317},"bash -c 'python -m debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn main:app --host 0.0.0.0 --port 8155 --reload'",[307,1974,1290],{"class":485},[186,1976,1977],{},"No worries, the following explains the parameter list:",[200,1979,1980,1986,1996,2005,2014],{},[203,1981,1982,1985],{},[413,1983,1984],{},"-i quay.io/gefyra/oauth2-demo",": run the Docker image which is also running in the cluster",[203,1987,1988,1991,1992,1995],{},[413,1989,1990],{},"-N myfastapi-demo",": name this local Docker instance ",[413,1993,1994],{},"myfastapi-demo"," for further reference",[203,1997,1998,2001,2002,2004],{},[413,1999,2000],{},"-n oauth2-demo",": place this Docker instance in the Kubernetes namespace ",[413,2003,604],{}," (where this example plays)",[203,2006,2007,2010,2011],{},[413,2008,2009],{},"-v /home/\u003C...>/gefyra-demos/oauth2-demo/app:/app",": mount the source code on your disk to this Docker instance at ",[413,2012,2013],{},"/app",[203,2015,2016,2019,2020,2027],{},[413,2017,2018],{},"-c \"CMD\"",": start this Docker instance with ",[190,2021,2024],{"href":2022,"rel":2023,"target":247},"https://github.com/microsoft/debugpy",[213],[413,2025,2026],{},"debugpy",", the rest is like from the Kubernetes workload manifest of the application",[186,2029,2030,2033,2034,2037],{},[190,2031,2026],{"href":2022,"rel":2032,"target":247},[213]," is an implementation of the ",[413,2035,2036],{},"Debug Adapter Protocol"," for Python. This protocol\nis also available for a countless number of programming languages. It basically spins up a server, in this case waiting for\na debugger client to connect, and runs the application wrapped in with debugging capabilities.",[524,2039,2041],{"id":2040},"attaching-a-debugger-to-the-development-instance","Attaching a Debugger to the Development Instance",[186,2043,2044,2045,2048,2049,2051],{},"Now that you are running a development instance with this Docker image locally, you need to connect the debugger client.\nThis example is prepared with ",[413,2046,2047],{},"VSCode"," and the Python extension installed.",[390,2050],{},"\nIn order to do that, you need to find out the local IP address Gefyra assigned to your container with:",[298,2053,2055],{"className":300,"code":2054,"language":302,"meta":303,"style":303},"docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myfastapi-demo\n",[251,2056,2057],{"__ignoreMap":303},[307,2058,2059,2062,2065,2068,2071,2074,2077],{"class":309,"line":310},[307,2060,2061],{"class":313},"docker",[307,2063,2064],{"class":317}," inspect",[307,2066,2067],{"class":317}," -f",[307,2069,2070],{"class":485}," '",[307,2072,2073],{"class":317},"{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}",[307,2075,2076],{"class":485},"'",[307,2078,2079],{"class":317}," myfastapi-demo\n",[186,2081,2082],{},"This will be part of the CLI soon (or maybe it already is). The command shown tells the IP of the container which is\nneeded for VSCode.",[186,2084,2085,2086,2091],{},"Please get the code for the backend application from ",[190,2087,2090],{"href":2088,"rel":2089,"target":247},"https://github.com/gefyrahq/gefyra-demos/tree/main/oauth2-demo/app",[213],"the repository"," and\nopen up VSCode.",[186,2093,2094,2095,2098,2099,2102],{},"Select the ",[413,2096,2097],{},"Remote Attach"," option to connect to the running debugpy instance at the given IP. The port is ",[413,2100,2101],{},"5678"," (please review the command above).",[186,2104,2105],{},[396,2106],{"alt":2107,"className":2108,"src":2109},"starting the VSCode remote debugger",[400],"/img/usecases_oauth2-demo_vscode1.png",[186,2111,2112,2113,2116],{},"In the ",[413,2114,2115],{},"DEBUG CONSOLE"," it will display the following output:",[298,2118,2123],{"className":2119,"code":2121,"language":2122},[2120],"language-text","INFO:     Will watch for changes in these directories: ['/app']\nINFO:     Uvicorn running on http://0.0.0.0:8155 (Press CTRL+C to quit)\nINFO:     Started reloader process [438166] using watchgod\n","text",[251,2124,2121],{"__ignoreMap":303},[186,2126,2127],{},"Awesome. You have a debugger connected to the development instance. Now it's time to receive a request from the oauth2-proxy container.",[524,2129,2131],{"id":2130},"bridging-the-development-instance-in-the-cluster","Bridging the Development Instance in the Cluster",[186,2133,2134,2135,2138,2139,2142,2143,2145],{},"In order to receive requests (i.e. traffic) from within the cluster, basically when you hit the route ",[190,2136,1609],{"href":1609,"rel":2137,"target":247},[213],"\nin your browser, a ",[251,2140,2141],{},"gefyra bridge ..."," is needed.",[390,2144],{},"\nJust create a bridge with:",[298,2147,2149],{"className":300,"code":2148,"language":302,"meta":303,"style":303},"> gefyra bridge -N myfastapi-demo -n oauth2-demo \\\n      --target deploy/oauth2-demo/oauth2-demo-app \\\n      --port 8155:8155\n\n[INFO] Creating bridge for Pod oauth2-demo-675f5c55b5-xxj57\n[INFO] Waiting for the bridge(s) to become active\n[INFO] Bridge myfastapi established\n",[251,2150,2151,2158,2168,2176,2180,2198,2224],{"__ignoreMap":303},[307,2152,2153,2155],{"class":309,"line":310},[307,2154,646],{"class":485},[307,2156,2157],{"class":649}," gefyra bridge -N myfastapi-demo -n oauth2-demo \\\n",[307,2159,2160,2163,2166],{"class":309,"line":653},[307,2161,2162],{"class":313},"      --target",[307,2164,2165],{"class":317}," deploy/oauth2-demo/oauth2-demo-app",[307,2167,1944],{"class":649},[307,2169,2170,2173],{"class":309,"line":660},[307,2171,2172],{"class":317},"      --port",[307,2174,2175],{"class":317}," 8155:8155\n",[307,2177,2178],{"class":309,"line":681},[307,2179,657],{"emptyLinePlaceholder":656},[307,2181,2182,2184,2187,2189,2192,2195],{"class":309,"line":714},[307,2183,1126],{"class":485},[307,2185,2186],{"class":649},"INFO",[307,2188,1704],{"class":485},[307,2190,2191],{"class":649}," Creating bridge ",[307,2193,2194],{"class":1718},"for",[307,2196,2197],{"class":649}," Pod oauth2-demo-675f5c55b5-xxj57\n",[307,2199,2200,2202,2204,2206,2209,2211,2214,2216,2219,2221],{"class":309,"line":739},[307,2201,1126],{"class":485},[307,2203,2186],{"class":649},[307,2205,1704],{"class":485},[307,2207,2208],{"class":649}," Waiting ",[307,2210,2194],{"class":1718},[307,2212,2213],{"class":649}," the bridge",[307,2215,838],{"class":485},[307,2217,2218],{"class":313},"s",[307,2220,253],{"class":485},[307,2222,2223],{"class":649}," to become active\n",[307,2225,2226,2228,2230,2232],{"class":309,"line":765},[307,2227,1126],{"class":485},[307,2229,2186],{"class":649},[307,2231,1704],{"class":485},[307,2233,2234],{"class":649}," Bridge myfastapi established\n",[186,2236,2237],{},"The parameter list specifies the following:",[200,2239,2240,2247,2254,2263,2269],{},[203,2241,2242,2244,2245],{},[413,2243,1990],{},": the bridge targets (on one end) the local Docker instance with the name ",[413,2246,1994],{},[203,2248,2249,2251,2252],{},[413,2250,2000],{},": the target workload (the other end of the bridge) is in the Kubernetes namespace ",[413,2253,604],{},[203,2255,2256,2259,2260,2262],{},[413,2257,2258],{},"--deployment oauth2-demo",": Gefyra intercepts all Pods of the Deployment ",[413,2261,604],{}," (don't confuse it with the name of the namespace)",[203,2264,2265,2268],{},[413,2266,2267],{},"--port 8155:8155",": the bridge to map port 8155 of the container in the cluster to 8155 on the local instance",[203,2270,2271,2274,2275],{},[413,2272,2273],{},"--container-name oauth2-demo-app",": since this Pod contains multiple containers (see the sidecar pattern above), Gefyra is asked to intercept the application container ",[413,2276,2277],{},"oauth2-demo-app",[524,2279,2281],{"id":2280},"debugging-the-application","Debugging the Application",[186,2283,2284],{},"Now you are ready to stop the execution of the code in your VSCode debugger.\nPlace the breakpoint anywhere near the position you would expect the error to happen:",[186,2286,2287],{},[396,2288],{"alt":2289,"className":2290,"src":2291},"breakpoint in VSCode",[400],"/img/usecases_oauth2-demo_vscode2.png",[186,2293,2294,2295,2298],{},"Point your browser to ",[190,2296,1609],{"href":1609,"rel":2297,"target":247},[213]," again.",[186,2300,2301],{},"Once you hit the breakpoint, you can easily look around and introspect the JWT (json web token) issued from Keycloak and\nverified with OAuth2-Proxy.",[186,2303,2304],{},[396,2305],{"alt":2306,"className":2307,"src":2308},"introspecting variables and the JWT token",[400],"/img/usecases_oauth2-demo_vscode3.png",[186,2310,2311,2312,2315],{},"As you may see, the key in the token is written in a lowercase \"email\". This is causing the ",[413,2313,2314],{},"KeyError: 'Email'"," resulting\nin a 500 error.",[186,2317,2318,2321],{},[337,2319,2320],{},"Remark:"," Of course you could have found this out reading the logs, but where is the fun? Anyway, debugging software is\na tool for hunting down causes of way more complex misbehaving then in this example.",[524,2323,2325],{"id":2324},"fixing-the-bug","Fixing the Bug",[186,2327,2328,2329,2332],{},"Since the development instance is started with your local source code mounted into the container and the ",[413,2330,2331],{},"--reload"," flag turned on,\nplease move on and fix this bug. The fix looks like this:",[298,2334,2336],{"className":1630,"code":2335,"language":1632,"meta":303,"style":303},"[...]\n        data = jwt.decode(x_forwarded_access_token, options={\"verify_signature\": False})\n        mail = data[\"email\"]  # the key is with a lowercase 'email'\n        return {\"item_id\": item_id, \"Email\": mail}\n[...]\n",[251,2337,2338,2346,2378,2401,2431],{"__ignoreMap":303},[307,2339,2340,2342,2344],{"class":309,"line":310},[307,2341,1126],{"class":485},[307,2343,1129],{"class":649},[307,2345,1132],{"class":485},[307,2347,2348,2350,2352,2354,2356,2358,2360,2362,2364,2366,2368,2370,2372,2374,2376],{"class":309,"line":653},[307,2349,1728],{"class":649},[307,2351,1731],{"class":485},[307,2353,1734],{"class":649},[307,2355,193],{"class":485},[307,2357,1739],{"class":1642},[307,2359,838],{"class":485},[307,2361,1744],{"class":1642},[307,2363,1688],{"class":485},[307,2365,1749],{"class":1679},[307,2367,1752],{"class":485},[307,2369,489],{"class":485},[307,2371,1757],{"class":317},[307,2373,489],{"class":485},[307,2375,416],{"class":485},[307,2377,1764],{"class":485},[307,2379,2380,2382,2384,2386,2388,2390,2393,2395,2397],{"class":309,"line":660},[307,2381,1769],{"class":649},[307,2383,1731],{"class":485},[307,2385,1774],{"class":649},[307,2387,1126],{"class":485},[307,2389,489],{"class":485},[307,2391,2392],{"class":317},"email",[307,2394,489],{"class":485},[307,2396,1704],{"class":485},[307,2398,2400],{"class":2399},"sHwdD","  # the key is with a lowercase 'email'\n",[307,2402,2403,2405,2407,2409,2411,2413,2415,2417,2419,2421,2423,2425,2427,2429],{"class":309,"line":681},[307,2404,1790],{"class":1718},[307,2406,1793],{"class":485},[307,2408,489],{"class":485},[307,2410,1680],{"class":317},[307,2412,489],{"class":485},[307,2414,416],{"class":485},[307,2416,1804],{"class":649},[307,2418,1688],{"class":485},[307,2420,1284],{"class":485},[307,2422,1781],{"class":317},[307,2424,489],{"class":485},[307,2426,416],{"class":485},[307,2428,1817],{"class":649},[307,2430,507],{"class":485},[307,2432,2433,2435,2437],{"class":309,"line":714},[307,2434,1126],{"class":485},[307,2436,1129],{"class":649},[307,2438,1132],{"class":485},[186,2440,2441,2442,2444,2445,2448],{},"Once you have saved the changes, the application is immediately restarted with the fixed code.",[390,2443],{},"\nThe output of the route ",[190,2446,1609],{"href":1609,"rel":2447,"target":247},[213]," is\nnow in the browser:",[298,2450,2452],{"className":476,"code":2451,"language":478,"meta":303,"style":303},"{\"item_id\":123,\"Email\":\"john@gefyra.dev\"}\n",[251,2453,2454],{"__ignoreMap":303},[307,2455,2456,2458,2460,2462,2464,2466,2468,2470,2472,2474,2476,2478,2480,2482,2484],{"class":309,"line":310},[307,2457,486],{"class":485},[307,2459,489],{"class":485},[307,2461,1680],{"class":492},[307,2463,489],{"class":485},[307,2465,416],{"class":485},[307,2467,1614],{"class":701},[307,2469,1688],{"class":485},[307,2471,489],{"class":485},[307,2473,1781],{"class":492},[307,2475,489],{"class":485},[307,2477,416],{"class":485},[307,2479,489],{"class":485},[307,2481,457],{"class":317},[307,2483,489],{"class":485},[307,2485,507],{"class":485},[186,2487,2488],{},"Awesome! Commit and push.",[186,2490,2491],{},"This way you can be quite sure that this will work in all Kubernetes environments provisioned with these workloads.",[186,2493,2494,2496],{},[337,2495,2320],{}," Gefyra is able to run and bridge as many applications as you need. This is useful in complex request/response\nscenarios with multiple involved services - and potentially all with a debugger attached. Isn't that neat?",[524,2498,2500],{"id":2499},"shutting-down-gefyra","Shutting Down Gefyra",[186,2502,2503,2504,2507],{},"In order to clean everything up, you can run ",[251,2505,2506],{},"gefyra down",". This will remove the running bridges and shut down the development\ncontainer instances. You will now find the cluster reset to the state with the original bug around. For the fix to become persistent\nyou will need to roll out a new version of the container image specified in the Kubernetes workload manifest.",[195,2509,2511],{"id":2510},"remove-the-development-infrastructure","Remove the Development Infrastructure",[186,2513,2514,2515,2517],{},"If you have initially created the development infrastructure using ",[251,2516,248],{}," you can now run:",[298,2519,2521],{"className":300,"code":2520,"language":302,"meta":303,"style":303},"> deck remove --cluster https://github.com/gefyrahq/gefyra-demos.git\n\n[INFO] Deleting the k3d cluster with name gefyra-demos\n",[251,2522,2523,2530,2534],{"__ignoreMap":303},[307,2524,2525,2527],{"class":309,"line":310},[307,2526,646],{"class":485},[307,2528,2529],{"class":649}," deck remove --cluster https://github.com/gefyrahq/gefyra-demos.git\n",[307,2531,2532],{"class":309,"line":653},[307,2533,657],{"emptyLinePlaceholder":656},[307,2535,2536,2538,2540,2542],{"class":309,"line":660},[307,2537,1126],{"class":485},[307,2539,2186],{"class":649},[307,2541,1704],{"class":485},[307,2543,2544],{"class":649}," Deleting the k3d cluster with name gefyra-demos\n",[186,2546,2547],{},"If you created the infrastructure yourself, you probably already know how to get rid of everything yourself ;-)",[195,2549,2551],{"id":2550},"additional-notes","Additional Notes",[186,2553,2554,2555,2560,2561,2566],{},"If you are developing django applications, be sure to check out ",[190,2556,2559],{"href":2557,"rel":2558,"target":247},"https://django-hurricane.io/",[213],"Django-Hurricane",", a Kubernetes-native\nstack specifically created for django and ",[190,2562,2565],{"href":2563,"rel":2564,"target":247},"https://github.com/Blueshoe/pycloak",[213],"Pycloak",", a package that's makes it super easy to integrate\nOpenID Connect/OAuth2 workflows in django.",[2568,2569,2570],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":303,"searchDepth":653,"depth":653,"links":2572},[2573,2574,2575,2576,2577,2582,2583,2591,2592],{"id":197,"depth":653,"text":198},{"id":232,"depth":653,"text":233},{"id":282,"depth":653,"text":283},{"id":374,"depth":653,"text":375},{"id":521,"depth":653,"text":522,"children":2578},[2579,2580,2581],{"id":526,"depth":660,"text":527},{"id":1097,"depth":660,"text":1098},{"id":1578,"depth":660,"text":1579},{"id":1602,"depth":653,"text":1603},{"id":1867,"depth":653,"text":1868,"children":2584},[2585,2586,2587,2588,2589,2590],{"id":1881,"depth":660,"text":1882},{"id":2040,"depth":660,"text":2041},{"id":2130,"depth":660,"text":2131},{"id":2280,"depth":660,"text":2281},{"id":2324,"depth":660,"text":2325},{"id":2499,"depth":660,"text":2500},{"id":2510,"depth":653,"text":2511},{"id":2550,"depth":653,"text":2551},"This example demonstrates how to develop a Kubernetes sidecar pattern for an OAuth2 (OpenID Connect) authorized backend service using Gefyra.","md",null,{},{"title":122,"icon":125},{"title":177,"description":2593},"mlQv6oqO2S0d54RMKTkmm-ZE-7xhVimyGeLHKSRjNyw",[2601,2603],{"title":117,"path":118,"stem":119,"description":2602,"icon":120,"children":-1},"This example demonstrates how to run a local Golang container with hot code reloading as part of your Kubernetes namespace.",{"title":127,"path":128,"stem":129,"description":2604,"icon":98,"children":-1},"This guide will show you how to use Gefyra for the local development of a Kubernetes Application running in GKE. Gefyra is able to spin up a local container which behaves like it was part of the cluster already. This way you can run services inside the cluster without abstaining from features like hot code reload. Sounds good? Lets go!",1775752112257]