{"id":52673,"date":"2025-09-12T02:47:51","date_gmt":"2025-09-12T02:47:51","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=52673"},"modified":"2025-09-12T02:49:40","modified_gmt":"2025-09-12T02:49:40","slug":"kubernetes-setting-up-oidc-amazon-cognito-alb-ingress-grpc-eks","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/kubernetes-setting-up-oidc-amazon-cognito-alb-ingress-grpc-eks\/","title":{"rendered":"Kubernetes: Setting up OIDC (Amazon Cognito) + ALB Ingress + gRPC (EKS)"},"content":{"rendered":"\n<p>Below is a <strong>complete, copy-pasteable, step-by-step guide<\/strong> to put <strong>OIDC (Amazon Cognito) + ALB Ingress + gRPC (EKS)<\/strong> behind your DNS with TLS. I\u2019ve included <strong>all commands, manifests, and verification steps<\/strong>. I also note exactly where to substitute your values.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Assumptions you already have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>An EKS cluster (your output earlier shows <code>v1.32.6-eks-*<\/code>), <code>kubectl<\/code> logged in.<\/li>\n\n\n\n<li><strong>AWS Load Balancer Controller<\/strong> installed and healthy.<\/li>\n\n\n\n<li>Region: <strong>ap-northeast-1 (Tokyo)<\/strong>.<\/li>\n\n\n\n<li>Desired host: <strong><code>raj.dev.aws.k8.rajesh.com<\/code><\/strong>.<\/li>\n\n\n\n<li>Namespace we\u2019ll use: <strong><code>grpcdemo<\/code><\/strong>.<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<p>Citations for critical behaviors (ALB OIDC annotations, callback URL, gRPC with ALB) are embedded where they matter. (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">0) Quick preflight checks (do these once)<\/h1>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># AWS CLI identity and region<\/span>\naws sts get-caller-identity\naws configure get region\n\n<span class=\"hljs-comment\"># EKS context<\/span>\nkubectl version --short\nkubectl get nodes -o wide\n\n<span class=\"hljs-comment\"># AWS Load Balancer Controller is present and healthy<\/span>\nkubectl -n kube-system get deploy aws-load-balancer-controller\nkubectl -n kube-system get pods -l app.kubernetes.io\/name=aws-load-balancer-controller -o wide\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>\u2705 If the controller isn\u2019t installed\/healthy, fix that first (Helm chart install per AWS docs). The controller <strong>must<\/strong> be able to read Ingresses and (for OIDC) read the <strong>OIDC client Secret<\/strong>. If your install lacks secret permissions, we\u2019ll add a RoleBinding in <strong>Step 5<\/strong>. (There\u2019s a known symptom: \u201ccannot get resource secrets\u201d for the controller.) (<a href=\"https:\/\/github.com\/aws\/aws-cdk\/issues\/33223?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1) DNS: create the host name for your ALB<\/h1>\n\n\n\n<p>We\u2019ll ultimately point <code>raj.dev.aws.evp.drivemode.com<\/code> to the <strong>ALB DNS name<\/strong> (e.g., <code>k8s-...ap-northeast-1.elb.amazonaws.com<\/code>) provisioned by your Ingress.<\/p>\n\n\n\n<p>If your hosted zone is in <strong>Route 53<\/strong>, prepare this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># (Optional) Identify your public hosted zone ID<\/span>\naws route53 <span class=\"hljs-keyword\">list<\/span>-hosted-zones | jq -r <span class=\"hljs-string\">'.HostedZones&#91;] | \"\\(.Name) \\(.Id)\"'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We\u2019ll come back after the ALB is created (Step 4) and add an <strong>A\/ALIAS<\/strong> to the ALB hostname. Until then, ensure your domain is owned\/managed by you.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2) TLS (ACM): request\/validate a certificate for your host<\/h1>\n\n\n\n<p>ALB in ap-northeast-1 <strong>must<\/strong> use an ACM cert <strong>in the same region<\/strong>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Replace with your exact host; you can also include a wildcard SAN if useful<\/span>\nCERT_ARN=$(aws acm request-certificate \\\n  --domain-name raj.dev.aws.evp.drivemode.com \\\n  --validation-method DNS \\\n  --region ap-northeast<span class=\"hljs-number\">-1<\/span> \\\n  --query CertificateArn --output text)\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"CERT_ARN=$CERT_ARN\"<\/span>\n\n<span class=\"hljs-comment\"># Find the DNS validation record to create<\/span>\naws acm describe-certificate --certificate-arn <span class=\"hljs-string\">\"$CERT_ARN\"<\/span> --region ap-northeast<span class=\"hljs-number\">-1<\/span> \\\n  --query <span class=\"hljs-string\">'Certificate.DomainValidationOptions&#91;].ResourceRecord'<\/span> --output table\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Create the returned <strong>CNAME<\/strong> in your DNS (Route 53 example):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Prepare a change batch file (edit with the Name\/Value shown in the previous command)<\/span>\ncat &gt; \/tmp\/acm-validate.json &lt;&lt;<span class=\"hljs-string\">'JSON'<\/span>\n{\n  <span class=\"hljs-string\">\"Comment\"<\/span>: <span class=\"hljs-string\">\"ACM validation CNAME\"<\/span>,\n  <span class=\"hljs-string\">\"Changes\"<\/span>: &#91;{\n    <span class=\"hljs-string\">\"Action\"<\/span>: <span class=\"hljs-string\">\"UPSERT\"<\/span>,\n    <span class=\"hljs-string\">\"ResourceRecordSet\"<\/span>: {\n      <span class=\"hljs-string\">\"Name\"<\/span>: <span class=\"hljs-string\">\"_&lt;from_describe&gt;.raj.dev.aws.evp.drivemode.com.\"<\/span>,\n      <span class=\"hljs-string\">\"Type\"<\/span>: <span class=\"hljs-string\">\"CNAME\"<\/span>,\n      <span class=\"hljs-string\">\"TTL\"<\/span>: <span class=\"hljs-number\">300<\/span>,\n      <span class=\"hljs-string\">\"ResourceRecords\"<\/span>: &#91;{ <span class=\"hljs-string\">\"Value\"<\/span>: <span class=\"hljs-string\">\"_&lt;target_from_describe&gt;.acm-validations.aws.\"<\/span> }]\n    }\n  }]\n}\nJSON\n\n<span class=\"hljs-comment\"># Apply to your hosted zone (substitute your HostedZoneId)<\/span>\naws route53 change-resource-record-sets \\\n  --hosted-zone-id Z1234567890ABC \\\n  --change-batch file:<span class=\"hljs-comment\">\/\/\/tmp\/acm-validate.json<\/span>\n\n<span class=\"hljs-comment\"># Wait for ACM to validate<\/span>\naws acm wait certificate-validated --certificate-arn <span class=\"hljs-string\">\"$CERT_ARN\"<\/span> --region ap-northeast<span class=\"hljs-number\">-1<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Keep <strong><code>$CERT_ARN<\/code><\/strong> handy\u2014we\u2019ll use it in the Ingress.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3) Amazon Cognito: Create OIDC User Pool + Domain + App Client<\/h1>\n\n\n\n<p>ALB OIDC requires a \u201cconfidential\u201d app client (i.e., with client secret) and your <strong>callback URL must be<\/strong><br><code>https:\/\/&lt;your-host&gt;\/oauth2\/idpresponse<\/code> (ALB hard-codes this path). (<a href=\"https:\/\/docs.aws.amazon.com\/elasticloadbalancing\/latest\/application\/listener-authenticate-users.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.1 Create a user pool (CLI)<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Create a minimal user pool<\/span>\nPOOL_ID=$(aws cognito-idp create-user-pool \\\n  --pool-name <span class=\"hljs-string\">\"grpcdemo-pool\"<\/span> \\\n  --policies <span class=\"hljs-string\">'{\"PasswordPolicy\":{\"MinimumLength\":8,\"RequireUppercase\":true,\"RequireLowercase\":true,\"RequireNumbers\":true,\"RequireSymbols\":false}}'<\/span> \\\n  --region ap-northeast<span class=\"hljs-number\">-1<\/span> \\\n  --query <span class=\"hljs-string\">'UserPool.Id'<\/span> --output text)\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"POOL_ID=$POOL_ID\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">3.2 Create a user pool domain (Hosted UI)<\/h3>\n\n\n\n<p>Pick a unique <strong>domain prefix<\/strong> (all lowercase). For example: <code>raj-evp-demo<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">DOMAIN_PREFIX=raj-evp-demo\naws cognito-idp create-user-pool-domain \\\n  --domain $DOMAIN_PREFIX \\\n  --user-pool-id $POOL_ID \\\n  --region ap-northeast<span class=\"hljs-number\">-1<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Your <strong>Hosted UI base<\/strong> will be:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">https:\/\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DOMAIN_PREFIX<\/span>&gt;<\/span>.auth.ap-northeast-1.amazoncognito.com\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">3.3 Create an app client (with secret), enable Code flow and scopes<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">CALLBACK_URL=<span class=\"hljs-string\">\"https:\/\/raj.dev.aws.evp.drivemode.com\/oauth2\/idpresponse\"<\/span>   <span class=\"hljs-comment\"># critical!<\/span>\nSIGNOUT_URL=<span class=\"hljs-string\">\"https:\/\/raj.dev.aws.evp.drivemode.com\/\"<\/span>\n\nAPP_OUT=$(aws cognito-idp create-user-pool-client \\\n  --user-pool-id $POOL_ID \\\n  --client-name grpcdemo-app \\\n  --generate-secret \\\n  --allowed-o-auth-flows code \\\n  --allowed-o-auth-scopes <span class=\"hljs-string\">\"openid\"<\/span> <span class=\"hljs-string\">\"email\"<\/span> <span class=\"hljs-string\">\"profile\"<\/span> \\\n  --allowed-o-auth-flows-user-pool-client \\\n  --callback-urls <span class=\"hljs-string\">\"$CALLBACK_URL\"<\/span> \\\n  --logout-urls <span class=\"hljs-string\">\"$SIGNOUT_URL\"<\/span> \\\n  --region ap-northeast<span class=\"hljs-number\">-1<\/span> \\\n  --query <span class=\"hljs-string\">'UserPoolClient.{Id:ClientId,Secret:ClientSecret}'<\/span> --output json)\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"$APP_OUT\"<\/span>\nAPP_CLIENT_ID=$(<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"$APP_OUT\"<\/span> | jq -r .Id)\nAPP_CLIENT_SECRET=$(<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"$APP_OUT\"<\/span> | jq -r .Secret)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>OIDC endpoints<\/strong> for your Ingress annotations are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>issuer<\/strong>: <code>https:\/\/cognito-idp.ap-northeast-1.amazonaws.com\/&lt;POOL_ID&gt;<\/code><\/li>\n\n\n\n<li><strong>authorizationEndpoint<\/strong>: <code>https:\/\/&lt;DOMAIN_PREFIX&gt;.auth.ap-northeast-1.amazoncognito.com\/oauth2\/authorize<\/code><\/li>\n\n\n\n<li><strong>tokenEndpoint<\/strong>: <code>https:\/\/&lt;DOMAIN_PREFIX&gt;.auth.ap-northeast-1.amazoncognito.com\/oauth2\/token<\/code><\/li>\n\n\n\n<li><strong>userInfoEndpoint<\/strong>: <code>https:\/\/&lt;DOMAIN_PREFIX&gt;.auth.ap-northeast-1.amazoncognito.com\/oauth2\/userInfo<\/code><\/li>\n<\/ul>\n\n\n\n<p>(These are the required keys for the ALB OIDC annotation. (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>))<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.4 (Optional) Create a test user<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">aws cognito-idp admin-create-user \\\n  --user-pool-id $POOL_ID \\\n  --username rajesh@example.com \\\n  --temporary-password <span class=\"hljs-string\">'MyTempP@ssw0rd'<\/span> \\\n  --user-attributes Name=email,Value=rajesh@example.com Name=email_verified,Value=<span class=\"hljs-keyword\">true<\/span> \\\n  --message-action SUPPRESS \\\n  --region ap-northeast<span class=\"hljs-number\">-1<\/span>\n\n<span class=\"hljs-comment\"># Set a permanent password<\/span>\naws cognito-idp admin-set-user-password \\\n  --user-pool-id $POOL_ID \\\n  --username rajesh@example.com \\\n  --password <span class=\"hljs-string\">'MyPermP@ssw0rd!'<\/span> \\\n  --permanent \\\n  --region ap-northeast<span class=\"hljs-number\">-1<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4) Kubernetes namespace + app (gRPC server + HTTP health)<\/h1>\n\n\n\n<p>We\u2019ll run <strong><code>moul\/grpcbin<\/code><\/strong> (gRPC server) and a tiny <strong>HTTP echo<\/strong> container for ALB health checks. grpcbin exposes gRPC on <strong>9000<\/strong> (plaintext). (<a href=\"https:\/\/hub.docker.com\/r\/moul\/grpcbin?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Docker Hub<\/a>)<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Namespace<\/span>\nkubectl create <span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">grpcdemo<\/span> || <span class=\"hljs-title\">true<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">4.1 Deploy the app + service<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># file: grpcbin.yaml<\/span>\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: whoami\n  <span class=\"hljs-keyword\">namespace<\/span>: <span class=\"hljs-title\">grpcdemo<\/span>\n<span class=\"hljs-title\">spec<\/span>:\n  <span class=\"hljs-title\">replicas<\/span>: 1\n  <span class=\"hljs-title\">selector<\/span>: { <span class=\"hljs-title\">matchLabels<\/span>: { <span class=\"hljs-title\">app<\/span>: <span class=\"hljs-title\">whoami<\/span> } }\n  <span class=\"hljs-title\">template<\/span>:\n    <span class=\"hljs-title\">metadata<\/span>: { <span class=\"hljs-title\">labels<\/span>: { <span class=\"hljs-title\">app<\/span>: <span class=\"hljs-title\">whoami<\/span> } }\n    <span class=\"hljs-title\">spec<\/span>:\n      <span class=\"hljs-title\">containers<\/span>:\n        - <span class=\"hljs-title\">name<\/span>: <span class=\"hljs-title\">grpcbin<\/span>\n          <span class=\"hljs-title\">image<\/span>: <span class=\"hljs-title\">moul<\/span>\/<span class=\"hljs-title\">grpcbin<\/span>:<span class=\"hljs-title\">latest<\/span>\n          <span class=\"hljs-title\">ports<\/span>:\n            - <span class=\"hljs-title\">containerPort<\/span>: 9000   # <span class=\"hljs-title\">gRPC<\/span> <span class=\"hljs-title\">plaintext<\/span>\n          # <span class=\"hljs-title\">readiness<\/span>\/<span class=\"hljs-title\">liveness<\/span> <span class=\"hljs-title\">omitted<\/span> <span class=\"hljs-title\">for<\/span> <span class=\"hljs-title\">simplicity<\/span> (<span class=\"hljs-title\">gRPC<\/span>)\n        - <span class=\"hljs-title\">name<\/span>: <span class=\"hljs-title\">health<\/span>\n          <span class=\"hljs-title\">image<\/span>: <span class=\"hljs-title\">mendhak<\/span>\/<span class=\"hljs-title\">http<\/span>-<span class=\"hljs-title\">https<\/span>-<span class=\"hljs-title\">echo<\/span>:30\n          <span class=\"hljs-title\">env<\/span>:\n            - <span class=\"hljs-title\">name<\/span>: <span class=\"hljs-title\">PORT<\/span>\n              <span class=\"hljs-title\">value<\/span>: \"8080\"\n          <span class=\"hljs-title\">ports<\/span>:\n            - <span class=\"hljs-title\">containerPort<\/span>: 8080   # <span class=\"hljs-title\">HTTP<\/span> 200 <span class=\"hljs-title\">on<\/span> \"\/\"\n---\n<span class=\"hljs-title\">apiVersion<\/span>: <span class=\"hljs-title\">v1<\/span>\n<span class=\"hljs-title\">kind<\/span>: <span class=\"hljs-title\">Service<\/span>\n<span class=\"hljs-title\">metadata<\/span>:\n  <span class=\"hljs-title\">name<\/span>: <span class=\"hljs-title\">whoami<\/span>\n  <span class=\"hljs-title\">namespace<\/span>: <span class=\"hljs-title\">grpcdemo<\/span>\n<span class=\"hljs-title\">spec<\/span>:\n  <span class=\"hljs-title\">selector<\/span>: { <span class=\"hljs-title\">app<\/span>: <span class=\"hljs-title\">whoami<\/span> }\n  <span class=\"hljs-title\">ports<\/span>:\n    - <span class=\"hljs-title\">name<\/span>: <span class=\"hljs-title\">grpc<\/span>\n      <span class=\"hljs-title\">port<\/span>: 9000\n      <span class=\"hljs-title\">targetPort<\/span>: 9000\n      <span class=\"hljs-title\">protocol<\/span>: <span class=\"hljs-title\">TCP<\/span>\n    - <span class=\"hljs-title\">name<\/span>: <span class=\"hljs-title\">health<\/span>\n      <span class=\"hljs-title\">port<\/span>: 8080\n      <span class=\"hljs-title\">targetPort<\/span>: 8080\n      <span class=\"hljs-title\">protocol<\/span>: <span class=\"hljs-title\">TCP<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Apply and verify:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl apply -f grpcbin.yaml\nkubectl -n grpcdemo rollout status deploy\/whoami\nkubectl -n grpcdemo <span class=\"hljs-keyword\">get<\/span> pods -o wide\nkubectl -n grpcdemo <span class=\"hljs-keyword\">get<\/span> svc whoami -o wide\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5) OIDC client secret (and RBAC binding, if needed)<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">5.1 Create the <strong>Secret<\/strong> with Cognito app client creds<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"># file: oidc-client-secret.yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: oidc-client\n  namespace: grpcdemo\ntype: Opaque\nstringData:\n  clientID: \"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">APP_CLIENT_ID<\/span>&gt;<\/span>\"        # paste APP_CLIENT_ID from Step 3\n  clientSecret: \"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">APP_CLIENT_SECRET<\/span>&gt;<\/span>\" # paste APP_CLIENT_SECRET from Step 3\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">kubectl apply -f oidc-client-secret.yaml\nkubectl -n grpcdemo get secret oidc-client -o yaml | sed -n <span class=\"hljs-string\">'1,30p'<\/span>   <span class=\"hljs-comment\"># just to confirm keys exist (values are base64)<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">5.2 (Only if necessary) Bind the controller to read this Secret<\/h3>\n\n\n\n<p>Most recent Helm installs of the AWS LB Controller already have cluster-wide <code>get\/list\/watch<\/code> on <code>secrets<\/code>. If your logs show <strong><code>cannot get resource \"secrets\"<\/code><\/strong>, bind it:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\"># file: alb-controller-can-read-oidc-secret.yaml\napiVersion: rbac.authorization.k8s.io\/v1\nkind: Role\nmetadata:\n  name: alb-can-read-oidc-secret\n  namespace: grpcdemo\nrules:\n  - apiGroups: &#91;\"\"]\n    resources: &#91;\"secrets\"]\n    resourceNames: &#91;\"oidc-client\"]\n    verbs: &#91;\"get\"]\n---\napiVersion: rbac.authorization.k8s.io\/v1\nkind: RoleBinding\nmetadata:\n  name: alb-can-read-oidc-secret\n  namespace: grpcdemo\nsubjects:\n  - kind: ServiceAccount\n    name: aws-load-balancer-controller\n    namespace: kube-system\nroleRef:\n  kind: Role\n  name: alb-can-read-oidc-secret\n  apiGroup: rbac.authorization.k8s.io\n<\/code><\/span><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">kubectl<\/span> <span class=\"hljs-selector-tag\">apply<\/span> <span class=\"hljs-selector-tag\">-f<\/span> <span class=\"hljs-selector-tag\">alb-controller-can-read-oidc-secret<\/span><span class=\"hljs-selector-class\">.yaml<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>(Reference to the class of issue this avoids.) (<a href=\"https:\/\/github.com\/aws\/aws-cdk\/issues\/33223?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6) Ingress (ALB) with <strong>TLS<\/strong>, <strong>OIDC<\/strong>, and <strong>gRPC<\/strong><\/h1>\n\n\n\n<p>This Ingress:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Terminates TLS at ALB using your <strong>ACM cert<\/strong>.<\/li>\n\n\n\n<li>Uses <strong>OIDC<\/strong> with Cognito (code flow + <code>openid email profile<\/code> scopes). (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>)<\/li>\n\n\n\n<li>Sends <strong>gRPC<\/strong> traffic (HTTP\/2) to port <strong>9000<\/strong>.<\/li>\n\n\n\n<li>Uses an HTTP health check on port <strong>8080<\/strong>.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"># file: ingress-grpc-oidc.yaml\napiVersion: networking.k8s.io\/v1\nkind: Ingress\nmetadata:\n  name: grpcdemo-auth\n  namespace: grpcdemo\n  annotations:\n    # Share an existing ALB across ingresses (optional)\n    alb.ingress.kubernetes.io\/group.name: single-alb\n\n    # ALB essentials\n    alb.ingress.kubernetes.io\/scheme: internet-facing\n    alb.ingress.kubernetes.io\/target-type: ip\n    alb.ingress.kubernetes.io\/ip-address-type: ipv4\n    alb.ingress.kubernetes.io\/listen-ports: '&#91;{\"HTTP\":80,\"HTTPS\":443}]'\n    alb.ingress.kubernetes.io\/certificate-arn: \"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PUT_YOUR_$CERT_ARN_HERE<\/span>&gt;<\/span>\"\n    alb.ingress.kubernetes.io\/ssl-redirect: \"443\"\n\n    # Backend is gRPC (HTTP\/2)\n    alb.ingress.kubernetes.io\/backend-protocol-version: GRPC\n\n    # Health check (HTTP on the sidecar)\n    alb.ingress.kubernetes.io\/healthcheck-port: \"8080\"\n    alb.ingress.kubernetes.io\/healthcheck-path: \/\n    alb.ingress.kubernetes.io\/success-codes: \"200-399\"\n\n    # OIDC authentication (Cognito)\n    alb.ingress.kubernetes.io\/auth-type: oidc\n    alb.ingress.kubernetes.io\/auth-idp-oidc: &gt;\n      {\"issuer\":\"https:\/\/cognito-idp.ap-northeast-1.amazonaws.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">POOL_ID<\/span>&gt;<\/span>\",\n       \"authorizationEndpoint\":\"https:\/\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DOMAIN_PREFIX<\/span>&gt;<\/span>.auth.ap-northeast-1.amazoncognito.com\/oauth2\/authorize\",\n       \"tokenEndpoint\":\"https:\/\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DOMAIN_PREFIX<\/span>&gt;<\/span>.auth.ap-northeast-1.amazoncognito.com\/oauth2\/token\",\n       \"userInfoEndpoint\":\"https:\/\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DOMAIN_PREFIX<\/span>&gt;<\/span>.auth.ap-northeast-1.amazoncognito.com\/oauth2\/userInfo\",\n       \"secretName\":\"oidc-client\"}\n    alb.ingress.kubernetes.io\/auth-on-unauthenticated-request: authenticate\n    alb.ingress.kubernetes.io\/auth-scope: \"openid email profile\"\nspec:\n  ingressClassName: alb\n  rules:\n    - host: raj.dev.aws.evp.drivemode.com\n      http:\n        paths:\n          # gRPC endpoint (protected by OIDC)\n          - path: \/grpc\n            pathType: Prefix\n            backend:\n              service:\n                name: whoami\n                port:\n                  name: grpc\n          # Simple HTTP endpoint (also protected) to force the browser login flow\n          - path: \/whoami\n            pathType: Prefix\n            backend:\n              service:\n                name: whoami\n                port:\n                  name: health\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Apply and watch:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">kubectl apply -f ingress-grpc-oidc.yaml\n\n<span class=\"hljs-comment\"># Inspect the Ingress until an address\/hostname appears (ALB created)<\/span>\nkubectl -n grpcdemo get ing grpcdemo-auth -w\nkubectl -n grpcdemo describe ing grpcdemo-auth\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Get the ALB DNS name<\/strong> (you\u2019ll use this for Route 53 if not already set):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">ALB_DNS=$(kubectl -n grpcdemo get ing grpcdemo-auth -o jsonpath=<span class=\"hljs-string\">'{.status.loadBalancer.ingress&#91;0].hostname}'<\/span>)\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"$ALB_DNS\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7) Point your DNS name at the ALB<\/h1>\n\n\n\n<p>If not yet configured, create an <strong>A\/ALIAS<\/strong> to the ALB hostname:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">cat &gt; \/tmp\/alb-alias.json &lt;&lt;JSON\n{\n  <span class=\"hljs-string\">\"Comment\"<\/span>: <span class=\"hljs-string\">\"Alias for EKS ALB\"<\/span>,\n  <span class=\"hljs-string\">\"Changes\"<\/span>: &#91;{\n    <span class=\"hljs-string\">\"Action\"<\/span>: <span class=\"hljs-string\">\"UPSERT\"<\/span>,\n    <span class=\"hljs-string\">\"ResourceRecordSet\"<\/span>: {\n      <span class=\"hljs-string\">\"Name\"<\/span>: <span class=\"hljs-string\">\"raj.dev.aws.evp.drivemode.com.\"<\/span>,\n      <span class=\"hljs-string\">\"Type\"<\/span>: <span class=\"hljs-string\">\"A\"<\/span>,\n      <span class=\"hljs-string\">\"AliasTarget\"<\/span>: {\n        <span class=\"hljs-string\">\"HostedZoneId\"<\/span>: <span class=\"hljs-string\">\"Z14GRHDCWA56QT\"<\/span>,    <span class=\"hljs-comment\"># ALB zone id varies by region; ap-northeast-1 example, confirm in console<\/span>\n        <span class=\"hljs-string\">\"DNSName\"<\/span>: <span class=\"hljs-string\">\"$ALB_DNS\"<\/span>,\n        <span class=\"hljs-string\">\"EvaluateTargetHealth\"<\/span>: <span class=\"hljs-keyword\">false<\/span>\n      }\n    }\n  }]\n}\nJSON\n\naws route53 change-resource-record-sets \\\n  --hosted-zone-id Z1234567890ABC \\\n  --change-batch file:<span class=\"hljs-comment\">\/\/\/tmp\/alb-alias.json<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>(You can also CNAME if using a subzone; ALIAS A is preferred for the zone apex.)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">8) Verify <strong>target group health<\/strong> and OIDC flow<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">8.1 From Kubernetes side<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Pods, Endpoints<\/span>\nkubectl -n grpcdemo get pods -o wide\nkubectl -n grpcdemo get endpoints whoami\n\n<span class=\"hljs-comment\"># Ingress + annotations rendered correctly<\/span>\nkubectl -n grpcdemo describe ing grpcdemo-auth | sed -n <span class=\"hljs-string\">'1,200p'<\/span>\n\n<span class=\"hljs-comment\"># Controller logs (helpful if OIDC\/Secret isn\u2019t picked up)<\/span>\nkubectl -n kube-system logs -l app.kubernetes.io\/name=aws-load-balancer-controller --tail=<span class=\"hljs-number\">200<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">8.2 From AWS side<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In <strong>EC2 \u2192 Target Groups<\/strong>, find the TG(s) created for <code>grpcdemo-auth<\/code> rules.<\/li>\n\n\n\n<li>Check <strong>Targets<\/strong> tab \u2192 instance\/IP health status. If unhealthy:\n<ul class=\"wp-block-list\">\n<li>Health check path\/port not reachable: we set <code>8080<\/code> + <code>\/<\/code> to return <strong>200<\/strong>.<\/li>\n\n\n\n<li>Wrong success code: we allowed <code>\"200-399\"<\/code>.<\/li>\n\n\n\n<li>Timeout\/No route: confirm Security Groups and Pod is up.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>(Health check annotations and OIDC annotations are per AWS LB Controller docs. (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>))<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8.3 OIDC login &amp; browser test<\/h3>\n\n\n\n<p>Open:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">https:<span class=\"hljs-comment\">\/\/raj.dev.aws.evp.drivemode.com\/whoami<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You should be <strong>redirected<\/strong> to the Cognito Hosted UI, log in, then be returned to <code>\/oauth2\/idpresponse<\/code>, and finally <strong>proxied to your service<\/strong> with an <strong>ALB session cookie<\/strong> set. (The callback path requirement and flow are documented by AWS. (<a href=\"https:\/\/docs.aws.amazon.com\/elasticloadbalancing\/latest\/application\/listener-authenticate-users.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>))<\/p>\n\n\n\n<p>If you hit issues:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>redirect_mismatch<\/strong> \u2192 your Cognito app client must include the <strong>exact<\/strong> <code>https:\/\/raj.dev.aws.evp.drivemode.com\/oauth2\/idpresponse<\/code> (lowercase host). (<a href=\"https:\/\/docs.aws.amazon.com\/elasticloadbalancing\/latest\/application\/listener-authenticate-users.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/li>\n\n\n\n<li><strong>invalid_scope<\/strong> \u2192 ensure <code>alb.ingress.kubernetes.io\/auth-scope<\/code> scopes are enabled on your app client (<code>openid<\/code> mandatory; <code>email<\/code>, <code>profile<\/code> optional). (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>)<\/li>\n\n\n\n<li><strong>503 after login<\/strong> \u2192 targets unhealthy; fix health check path\/port or service wiring.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">9) Test <strong>gRPC<\/strong> through ALB<\/h1>\n\n\n\n<p>ALB will forward <strong>HTTP\/2<\/strong> to your backend for gRPC. (Official pattern confirms this setup.) (<a href=\"https:\/\/docs.aws.amazon.com\/prescriptive-guidance\/latest\/patterns\/deploy-a-grpc-based-application-on-an-amazon-eks-cluster-and-access-it-with-an-application-load-balancer.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u26a0\ufe0f ALB OIDC uses <strong>browser redirects + session cookie<\/strong>. Non-browser gRPC clients don\u2019t follow redirects. Two practical ways to test:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Manual cookie injection<\/strong>: log in via <code>\/whoami<\/code> in a browser, copy the <code>AWSELBAuthSessionCookie*<\/code> cookie, then call gRPC with that cookie header.<\/li>\n\n\n\n<li>For automated programmatic gRPC auth, consider moving JWT verification to an Envoy\/NGINX gateway or API Gateway; ALB OIDC is primarily browser-centric. (<a href=\"https:\/\/aws.amazon.com\/blogs\/containers\/how-to-use-application-load-balancer-and-amazon-cognito-to-authenticate-users-for-your-kubernetes-web-apps\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Amazon Web Services, Inc.<\/a>)<\/li>\n<\/ol>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">9.1 Using <code>grpcurl<\/code> with cookie (manual)<\/h3>\n\n\n\n<p>In your browser DevTools (Application \u2192 Storage \u2192 Cookies), copy the full cookie string (often multiple cookie keys). Then:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Replace cookie string and host<\/span>\ngrpcurl -insecure \\\n  -authority raj.dev.aws.evp.drivemode.com \\\n  -H <span class=\"hljs-string\">'cookie: AWSELBAuthSessionCookie=...; AWSELBAuthSessionCookie-0=...'<\/span> \\\n  raj.dev.aws.evp.drivemode.com:<span class=\"hljs-number\">443<\/span> <span class=\"hljs-keyword\">list<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You should see grpcbin services (e.g., <code>grpcbin.GRPCBin<\/code>, reflection, etc.). If you prefer an actual RPC:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Example: server reflection enabled, list methods<\/span>\ngrpcurl -insecure \\\n  -authority raj.dev.aws.evp.drivemode.com \\\n  -H <span class=\"hljs-string\">'cookie: AWSELBAuthSessionCookie=...; AWSELBAuthSessionCookie-0=...'<\/span> \\\n  raj.dev.aws.evp.drivemode.com:<span class=\"hljs-number\">443<\/span> describe grpcbin.GRPCBin\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">10) Troubleshooting quick table<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Symptom<\/th><th>Likely cause<\/th><th>Fix<\/th><\/tr><\/thead><tbody><tr><td><code>redirect_mismatch<\/code> at Cognito<\/td><td>Callback URL not exactly <code>https:\/\/&lt;host&gt;\/oauth2\/idpresponse<\/code><\/td><td>Add exact callback URL to app client (lowercase host) and save. (<a href=\"https:\/\/docs.aws.amazon.com\/elasticloadbalancing\/latest\/application\/listener-authenticate-users.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/td><\/tr><tr><td><code>invalid_scope<\/code><\/td><td>Ingress requests scopes not enabled in app client<\/td><td>Enable <code>openid<\/code> (+ <code>email profile<\/code>) in app client, or reduce <code>auth-scope<\/code>. (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>)<\/td><\/tr><tr><td><code>401 Authorization Required<\/code> at <code>\/oauth2\/idpresponse<\/code><\/td><td>Wrong\/disabled OAuth flow or scopes<\/td><td>Ensure <strong>Authorization code flow<\/strong> + <code>openid<\/code> allowed on app client. (<a href=\"https:\/\/docs.aws.amazon.com\/elasticloadbalancing\/latest\/application\/listener-authenticate-users.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/td><\/tr><tr><td><code>503 Service Temporarily Unavailable<\/code> after login<\/td><td>No healthy targets<\/td><td>Use health sidecar on 8080 + <code>\/<\/code>, widen success codes; confirm Service\/Endpoints.<\/td><\/tr><tr><td>ALB never provisions<\/td><td>Controller missing permissions\/IRSA<\/td><td>Check controller logs; ensure it has required IAM and K8s RBAC.<\/td><\/tr><tr><td>Controller can\u2019t read OIDC Secret<\/td><td>RBAC mis-scoped<\/td><td>Apply the Role\/RoleBinding in Step 5.2. (<a href=\"https:\/\/github.com\/aws\/aws-cdk\/issues\/33223?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>)<\/td><\/tr><tr><td>gRPC client gets redirect \/ cannot auth<\/td><td>ALB OIDC is redirect-based<\/td><td>Use cookie injection (manual) or move JWT validation to an in-cluster gateway\/API Gateway. (<a href=\"https:\/\/aws.amazon.com\/blogs\/containers\/how-to-use-application-load-balancer-and-amazon-cognito-to-authenticate-users-for-your-kubernetes-web-apps\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Amazon Web Services, Inc.<\/a>)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">11) Clean, minimal <strong>re-run<\/strong> checklist<\/h1>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>ACM<\/strong> cert validated in <strong>ap-northeast-1<\/strong>; have <strong><code>$CERT_ARN<\/code><\/strong>.<\/li>\n\n\n\n<li><strong>Cognito<\/strong>: <code>POOL_ID<\/code>, <code>DOMAIN_PREFIX<\/code>, <strong>App Client (with secret)<\/strong>, callback set to <code>\/oauth2\/idpresponse<\/code>.<\/li>\n\n\n\n<li><strong>Kubernetes<\/strong>:\n<ul class=\"wp-block-list\">\n<li><code>grpcbin.yaml<\/code> applied (pod ready, service ports 9000 + 8080).<\/li>\n\n\n\n<li><code>oidc-client-secret.yaml<\/code> applied (with <code>clientID\/clientSecret<\/code>).<\/li>\n\n\n\n<li>(If needed) <code>alb-controller-can-read-oidc-secret.yaml<\/code> applied.<\/li>\n\n\n\n<li><code>ingress-grpc-oidc.yaml<\/code> applied; ALB DNS populated.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>DNS<\/strong>: Route 53 A\/ALIAS \u2192 ALB hostname.<\/li>\n\n\n\n<li><strong>Browser test<\/strong>: <code>https:\/\/raj.dev.aws.evp.drivemode.com\/whoami<\/code> \u2192 Cognito login \u2192 returns OK.<\/li>\n\n\n\n<li><strong>gRPC test<\/strong> (manual cookie) via <code>grpcurl<\/code>.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Reference docs used<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>AWS Load Balancer Controller \u2013 Ingress annotations<\/strong> (OIDC, health check, scopes, unauthenticated behavior). (<a href=\"https:\/\/kubernetes-sigs.github.io\/aws-load-balancer-controller\/v2.6\/guide\/ingress\/annotations\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Kubernetes SIGs<\/a>)<\/li>\n\n\n\n<li><strong>Application Load Balancer \u2013 Authenticate users (OIDC\/Cognito)<\/strong> (callback <code>\/oauth2\/idpresponse<\/code>, flows, permissions). (<a href=\"https:\/\/docs.aws.amazon.com\/elasticloadbalancing\/latest\/application\/listener-authenticate-users.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/li>\n\n\n\n<li><strong>AWS re:Post \u2013 ALB + Cognito callback<\/strong> (explicit <code>\/oauth2\/idpresponse<\/code> with ALB DNS\/your host). (<a href=\"https:\/\/repost.aws\/knowledge-center\/cognito-user-pool-alb-authentication?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Repost<\/a>)<\/li>\n\n\n\n<li><strong>EKS Prescriptive Guidance \u2013 gRPC behind ALB<\/strong> (HTTP\/2 TLS path). (<a href=\"https:\/\/docs.aws.amazon.com\/prescriptive-guidance\/latest\/patterns\/deploy-a-grpc-based-application-on-an-amazon-eks-cluster-and-access-it-with-an-application-load-balancer.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">AWS Documentation<\/a>)<\/li>\n\n\n\n<li><strong>AWS Containers Blog \u2013 Cognito auth for K8s apps<\/strong> (pattern background). (<a href=\"https:\/\/aws.amazon.com\/blogs\/containers\/how-to-use-application-load-balancer-and-amazon-cognito-to-authenticate-users-for-your-kubernetes-web-apps\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Amazon Web Services, Inc.<\/a>)<\/li>\n\n\n\n<li><strong>grpcbin image<\/strong> (ports &amp; usage). (<a href=\"https:\/\/hub.docker.com\/r\/moul\/grpcbin?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Docker Hub<\/a>)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Below is a complete, copy-pasteable, step-by-step guide to put OIDC (Amazon Cognito) + ALB Ingress + gRPC (EKS) behind your DNS with TLS. I\u2019ve included all commands, manifests, and verification&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-52673","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/52673","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=52673"}],"version-history":[{"count":3,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/52673\/revisions"}],"predecessor-version":[{"id":52676,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/52673\/revisions\/52676"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=52673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=52673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=52673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}