Cannot override boot config values using environment variables
jeekishy opened this issue · comments
Description
Cannot override boot config values for JWT Middleware from environment variables.
Steps to reproduce the behavior:
- Create boot.yaml file
echo:
- name: greeter
port: 8080
enabled: true
middleware:
jwt:
enabled: false
asymmetric:
algorithm: ""
publicKey: ""
privateKey: ""
- create a main.go file as per below and update environment variables for JWT token
package main
import (
"context"
"fmt"
"github.com/labstack/echo/v4"
rkboot "github.com/rookie-ninja/rk-boot/v2"
rkecho "github.com/rookie-ninja/rk-echo/boot"
"github.com/rookie-ninja/rk-echo/middleware/context"
"net/http"
"os"
)
func main() {
// ideally this will be added by CI/CD pipeline I have added this as an example
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ENABLED", "true")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_ALGORITHM", "ES256")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PUBLICKEY", "xxxxx")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PRIVATEKEY", "xxxxx")
// Create a new boot instance.
boot := rkboot.NewBoot()
// Register handler
echoEntry := rkecho.GetEchoEntry("greeter")
echoEntry.Echo.GET("/v1/greeter", Greeter)
// Bootstrap
boot.Bootstrap(context.TODO())
boot.WaitForShutdownSig(context.TODO())
}
func Greeter(ctx echo.Context) error {
// Get JWT token
rkechoctx.GetJwtToken(ctx)
return ctx.JSON(http.StatusOK, &GreeterResponse{
Message: fmt.Sprintf("Hello %s!", ctx.QueryParam("name")),
})
}
type GreeterResponse struct {
Message string
}
- Run program
go run main.go
➜ test git:(HB-13764---Initial-VMS-Service-and-Auth) ✗ go run main.go
2022-09-21T12:09:50.429+1000 INFO entry/util.go:299 Found ENV to override, applying... {"env": ["RK_ECHO_0_MIDDLEWARE_JWT_ENABLED=true => echo[0].middleware.jwt.enabled=true", "RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_ALGORITHM=ES256 => echo[0].middleware.jwt.asymmetric.algorithm=ES256", "RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PUBLICKEY=xxxxx => echo[0].middleware.jwt.asymmetric.publickey=xxxxx", "RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PRIVATEKEY=xxxxx => echo[0].middleware.jwt.asymmetric.privatekey=xxxxx"]}
2022-09-21T12:09:50.430+1000 INFO boot/echo_entry.go:682 Bootstrap EchoEntry {"eventId": "28f73547-7079-4fa1-a6e5-9483e761b44b", "entryName": "greeter", "entryType": "EchoEntry"}
------------------------------------------------------------------------
endTime=2022-09-21T12:09:50.430602+10:00
startTime=2022-09-21T12:09:50.430542+10:00
elapsedNano=59241
timezone=AEST
ids={"eventId":"28f73547-7079-4fa1-a6e5-9483e761b44b"}
app={"appName":"rk","appVersion":"local","entryName":"greeter","entryType":"EchoEntry"}
env={"arch":"amd64","domain":"*","hostname":"C02YX1MSLVCF","localIP":"10.131.145.133","os":"darwin"}
payloads={"echoPort":8080}
counters={}
pairs={}
timing={}
remoteAddr=localhost
operation=Bootstrap
resCode=OK
eventStatus=Ended
EOE
- Make a request with Authorization in header, the request should have failed as the certs provided is not valid.
➜ auth git:(HB-13764---Initial-VMS-Service-and-Auth) ✗ curl -XGET -H 'Authorization: eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjo0NzA2MSwidmFsaWRhdGVkIjp0cnVlfSwiY29tbW9uIjp7ImNsaWVudCI6MTQsImJ1aWxkaW5nIjoxNTIsInRlbmFudCI6ODIyfSwic2NvcGVzIjpbInVzZXIuYXBwLmFsbCJdLCJpc3MiOiJsb2NhbGhvc3QiLCJleHAiOjIyNjQ4NTUxNDF9.ywC-EiD-GCWPM3cEor5i0Jcmwb3-ASf8sUjJ2SdQy55MCr8s8fFO1Xm3itWLFQczU2toEdUZv96VcteU0eTBHA' 'http://localhost:8080/v1/greeter'
{"Message":"Hello !"}
Expected behavior
The above request should not validate passed to the handler as I have use the env to overide the boot variables.
Additional context
The reason we require this is because when deploying our micro-services using CI/CD pipeline the configurations will get injected during build as environment variables.
@jeekishy Hi,I will check the the problem happens in your example. There may be bugs in it.
@jeekishy There was a bug in rk-entry which failed to recognize fields in boot.yaml while it was nested.
New release of rk-xxx family has been published with bug fixes.
Bug fix: rookie-ninja/rk-entry@ddaec60
In your case, please update bellow dependencies with newest version.
- rk-boot: v2.2.6
- rk-echo: v1.2.7
Reproduce
0: Bump up rk-boot and rk-echo dependencies
require (
github.com/labstack/echo/v4 v4.7.2
github.com/rookie-ninja/rk-boot/v2 v2.2.6
github.com/rookie-ninja/rk-echo v1.2.7
)
1: Create ES256 key pair
openssl ecparam -name prime256v1 -genkey -noout -out private.ec.key
openssl ec -in private.ec.key -pubout -out public.pem
2: Create boot.yaml
echo:
- name: greeter
port: 8080
enabled: true
middleware:
jwt:
enabled: false
asymmetric:
algorithm: ""
publicKey: ""
privateKey: ""
3: Create main.go
package main
import (
"context"
"fmt"
"github.com/labstack/echo/v4"
"github.com/rookie-ninja/rk-boot/v2"
"github.com/rookie-ninja/rk-echo/boot"
"github.com/rookie-ninja/rk-echo/middleware/context"
"net/http"
"os"
)
func main() {
// ideally this will be added by CI/CD pipeline I have added this as an example
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ENABLED", "true")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_ALGORITHM", "ES256")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PUBLICKEY", "paste pub key generated before")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PRIVATEKEY", "paste private key generated before")
// Create a new boot instance.
boot := rkboot.NewBoot()
// Register handler
echoEntry := rkecho.GetEchoEntry("greeter")
echoEntry.Echo.GET("/v1/greeter", Greeter)
// Bootstrap
boot.Bootstrap(context.TODO())
boot.WaitForShutdownSig(context.TODO())
}
func Greeter(ctx echo.Context) error {
// Get JWT token
rkechoctx.GetJwtToken(ctx)
return ctx.JSON(http.StatusOK, &GreeterResponse{
Message: fmt.Sprintf("Hello %s!", ctx.QueryParam("name")),
})
}
type GreeterResponse struct {
Message string
}
4: Run program
go run main.go
2022-09-22T00:23:37.405+0800 INFO entry/util.go:354 Found ENV to override, applying... {"env": ["RK_ECHO_0_MIDDLEWARE_JWT_ENABLED=true => echo[0].middleware.jwt.enabled=true", "RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_ALGORITHM=ES256 => echo[0].middleware.jwt.asymmetric.algorithm=ES256", "RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PUBLICKEY=xxxx => echo[0].middleware.jwt.asymmetric.publickey=xxxx", "RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PRIVATEKEY=xxxx => echo[0].middleware.jwt.asymmetric.privatekey=xxxx"]}
2022-09-22T00:23:37.406+0800 INFO boot/echo_entry.go:682 Bootstrap EchoEntry {"eventId": "91843a4c-0e6a-4400-909e-bd17a0e5743a", "entryName": "greeter", "entryType": "EchoEntry"}
------------------------------------------------------------------------
endTime=2022-09-22T00:23:37.40694+08:00
startTime=2022-09-22T00:23:37.406892+08:00
elapsedNano=47378
timezone=CST
ids={"eventId":"91843a4c-0e6a-4400-909e-bd17a0e5743a"}
app={"appName":"rk","appVersion":"local","entryName":"greeter","entryType":"EchoEntry"}
env={"arch":"amd64","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin"}
payloads={"echoPort":8080}
counters={}
pairs={}
timing={}
remoteAddr=localhost
operation=Bootstrap
resCode=OK
eventStatus=Ended
EOE
5: Make request
curl -XGET -H 'Authorization: Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjo0NzA2MSwidmFsaWRhdGVkIjp0cnVlfSwiY29tbW9uIjp7ImNsaWVudCI6MTQsImJ1aWxkaW5nIjoxNTIsInRlbmFudCI6ODIyfSwic2NvcGVzIjpbInVzZXIuYXBwLmFsbCJdLCJpc3MiOiJsb2NhbGhvc3QiLCJleHAiOjIyNjQ4NTUxNDF9.ywC-EiD-GCWPM3cEor5i0Jcmwb3-ASf8sUjJ2SdQy55MCr8s8fFO1Xm3itWLFQczU2toEdUZv96VcteU0eTBHB' 'http://localhost:8080/v1/greeter'
{"error":{"code":401,"status":"Unauthorized","message":"Invalid or expired jwt","details":[]}}
Prevent print private keys in log
In order to prevent program print overridden keys in log, we can override pub key and private key with path.
boot.yaml
echo:
- name: greeter
port: 8080
enabled: true
middleware:
jwt:
enabled: false
asymmetric:
algorithm: ""
publicKeyPath: ""
privateKeyPath: ""
main.go
package main
import (
"context"
"fmt"
"github.com/labstack/echo/v4"
"github.com/rookie-ninja/rk-boot/v2"
"github.com/rookie-ninja/rk-echo/boot"
"github.com/rookie-ninja/rk-echo/middleware/context"
"net/http"
"os"
)
func main() {
// ideally this will be added by CI/CD pipeline I have added this as an example
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ENABLED", "true")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_ALGORITHM", "ES256")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PUBLICKEYPATH", "public.pem")
_ = os.Setenv("RK_ECHO_0_MIDDLEWARE_JWT_ASYMMETRIC_PRIVATEKEYPATH", "private.ec.key")
// Create a new boot instance.
boot := rkboot.NewBoot()
// Register handler
echoEntry := rkecho.GetEchoEntry("greeter")
echoEntry.Echo.GET("/v1/greeter", Greeter)
// Bootstrap
boot.Bootstrap(context.TODO())
boot.WaitForShutdownSig(context.TODO())
}
func Greeter(ctx echo.Context) error {
// Get JWT token
rkechoctx.GetJwtToken(ctx)
return ctx.JSON(http.StatusOK, &GreeterResponse{
Message: fmt.Sprintf("Hello %s!", ctx.QueryParam("name")),
})
}
type GreeterResponse struct {
Message string
}
@dongxuny thank you for the fast turn around. It is working as expected now. :)