Hide error message on Policy failure in Istio - istio

If I define an AuthorizationPolicy in Istio which is violated, the error message is returned to me, for example:
INTERNAL:performing check operation failed: 1 error occurred:%0A%09* rpc error: code = PermissionDenied desc = RBAC: access denied%0A%0A
Is there a way I can hide the message?
Istio version: 1.4.5

Based on below istio github code
// CheckRBACRequest checks if a request is successful under RBAC policies.
// Under RBAC policies, a request is consider successful if:
// * If the policy is allow:
// *** Response code is 200
// * If the policy is deny:
// *** For HTTP: response code is 403.
// *** For TCP: EOF error
func (tc TestCase) CheckRBACRequest() error {
req := tc.Request
headers := make(http.Header)
if len(tc.Jwt) > 0 {
headers.Add("Authorization", "Bearer "+tc.Jwt)
}
for k, v := range tc.Headers {
headers.Add(k, v)
}
tc.Request.Options.Headers = headers
resp, err := req.From.Call(tc.Request.Options)
if tc.ExpectAllowed {
if err == nil {
err = resp.CheckOK()
}
if err != nil {
return getError(req, "allow with code 200", fmt.Sprintf("error: %v", err))
}
} else {
if req.Options.PortName == "tcp" || req.Options.PortName == "grpc" {
expectedErrMsg := "EOF" // TCP deny message.
if req.Options.PortName == "grpc" {
expectedErrMsg = "rpc error: code = PermissionDenied desc = RBAC: access denied"
}
if err == nil || !strings.Contains(err.Error(), expectedErrMsg) {
expect := fmt.Sprintf("deny with %s error", expectedErrMsg)
actual := fmt.Sprintf("error: %v", err)
return getError(req, expect, actual)
}
} else {
if err != nil {
return getError(req, "deny with code 403", fmt.Sprintf("error: %v", err))
}
var result string
if len(resp) == 0 {
result = "no response"
} else if resp[0].Code != response.StatusCodeForbidden {
result = resp[0].Code
}
if result != "" {
return getError(req, "deny with code 403", result)
}
}
}
return nil
}
As far as I'm concerned, and based on above code, you would have to actually change istio code to achieve what you need.

Related

how to fix Cosmos RPC Endpoint CORS Error

I am building a dApp using #cosmjs.
I want to make a transaction on the COSMOS chain on my dApp running on the JUNO chain.
When I tried to get the signingClient, I got the following running error.
TypeError: Failed to fetch
at http (http://localhost:3000/static/js/bundle.js:53443:12)
at HttpClient.execute (http://localhost:3000/static/js/bundle.js:53471:65)
at Tendermint34Client.detectVersion (http://localhost:3000/static/js/bundle.js:55135:35)
at Tendermint34Client.create (http://localhost:3000/static/js/bundle.js:55128:33)
at Tendermint34Client.connect (http://localhost:3000/static/js/bundle.js:55115:33)
at SigningCosmWasmClient.connectWithSigner (http://localhost:3000/static/js/bundle.js:23403:64)
at http://localhost:3000/static/js/bundle.js:127476:51
at Generator.next (<anonymous>)
at fulfilled (http://localhost:3000/static/js/bundle.js:462877:24)
Here is my code;
import { SigningCosmWasmClient } from "#cosmjs/cosmwasm-stargate";
import { GasPrice }from "#cosmjs/stargate";
.....
const config = {
chainName: "Cosmos Hub",
chainId: "cosmoshub-4",
rpcEndpoint: "https://rpc-cosmoshub.whispernode.com",
restEndpoint: "",
faucetEndpoint: "",
addressPrefix: "cosmos",
microDenom: "uatom",
coinDecimals: "6",
gasPrice: "0.025",
}
.....
await window.keplr?.enable(config.chainId);
const offlineSigner= window.getOfflineSigner?.(
config.chainId
);
const account = await offlineSigner?.getAccounts();
let wasmChainClient = null;
if (offlineSigner) {
try {
wasmChainClient = await SigningCosmWasmClient.connectWithSigner(
config.rpcEndpoint,
offlineSigner,
{
gasPrice: GasPrice.fromString(
`${config.gasPrice}${config.microDenom}`
),
}
);
} catch (e) {
console.error("wallets", e);
}
}
const result= {
account: account?.[0],
client: wasmChainClient,
};
console.log(result)
Is this the problem of rpc endpoint?
I have tried other several rpc endpoints but all of them failed.
I really don't know why this happens.
I would be very thankful if anyone could help me with solving this issue.
This happens because your browser blocks request with different origin. Your origin is http://localhost:3000, and you requested https://rpc-cosmoshub.keplr.app. So, your browser blocks the response of the requested origin if there is no access-control-allow-origin header in the response. You can learn more here (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors).
I have a workaround program that adds necessary headers to a response.
You have to have golang to run it.
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
)
var hostname string
var port int
func main() {
// flags declaration using flag package
flag.StringVar(&hostname, "H", "https://rpc-cosmoshub.keplr.app", "Specify hostname")
flag.IntVar(&port, "p", 8081, "Specify port")
flag.Parse() // after declaring flags we
http.HandleFunc("/", serveCorsProxy)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}
// Serve a reverse proxy for a given url
func serveCorsProxy(res http.ResponseWriter, req *http.Request) {
proxyRequest, err := http.NewRequest(req.Method, hostname, req.Body)
proxyRequest.URL.Path = req.URL.Path
proxyRequest.URL.RawQuery = req.URL.RawQuery
if err != nil {
fmt.Printf("create request error: %v", err)
return
}
response, err := http.DefaultClient.Do(proxyRequest)
if err != nil {
fmt.Printf("proxy request error: %v", err)
return
}
setHeaders(response, &res)
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Printf("response read error: %v", err)
return
}
res.WriteHeader(response.StatusCode)
_, _ = res.Write(body)
}
func setHeaders(src *http.Response, dest *http.ResponseWriter) {
header := (*dest).Header()
for name, values := range (*src).Header {
for _, value := range values {
header.Set(name, value)
}
}
header.Set("access-control-allow-headers", "Accept,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With")
header.Set("access-control-allow-methods", "GET, POST, OPTIONS")
header.Set("access-control-allow-origin", "*")
header.Set("access-control-expose-headers", "Content-Length,Content-Range")
header.Set("access-control-max-age", "1728000")
}
You have to save it to file main.go and run by go run main.go -H https://rpc-cosmoshub.keplr.app -p 3001.
After that you can access the RPC on localhost:3001

AWS lambda function to upload file

I am trying to upload a file using APIGateway and Lambda (Go). Idea is to upload the file and then move that file to S3 bucket. But for some reason I keep getting an error. Here is my code.
func parse(request events.APIGatewayProxyRequest) {
var fileBytes []byte
var filename, contentType string
contentType, params, parseErr := mime.ParseMediaType(request.Headers["Content-Type"])
fmt.Printf("DEBUG:: contentType: %v\n", contentType)
if parseErr != nil || !strings.HasPrefix(contentType, "multipart/") {
logger.Instance.Error("unexpected error when retrieving a part of the message", zap.Error(parseErr))
return
}
fmt.Printf("DEBUG:: request body: %v\n", request.Body)
multipartReader := multipart.NewReader(strings.NewReader(request.Body), params["boundary"])
// defer request.Body.Close()
for {
part, err := multipartReader.NextPart()
if err == io.EOF {
break
}
if err != nil {
logger.Instance.Error("unexpected error when retrieving a part of the message", zap.Error(err))
return
}
defer part.Close()
fileBytes, err = ioutil.ReadAll(part)
if err != nil {
logger.Instance.Error("failed to read content of the part", zap.Error(err))
return
}
}
logger.Instance.Info("handler.parseForm", zap.String("ParseForm", filename))
logger.Instance.Info("handler.parseForm", zap.String("ParseForm", contentType))
logger.Instance.Info("handler.parseForm", zap.Int("ParseForm", len(fileBytes)))
}
I get the following Error:
{
"level": "error",
"ts": 1614221323.4001436,
"caller": "uploadsvc/uploadsvc.go:53",
"msg": "unexpected error when retrieving a part of the message",
**"error": "multipart: NextPart: bufio: buffer full",**
"stacktrace": "main.parse\n\t/home/sarvs/go-workspace/src/uploadsvc/uploadsvc.go:53\nmain.handler\n\t/home/sarvs/go-workspace/src/uploadsvc/uploadsvc.go:144\nreflect.Value.call\n\t/snap/go/7013/src/reflect/value.go:476\nreflect.Value.Call\n\t/snap/go/7013/src/reflect/value.go:337\ngithub.com/aws/aws-lambda-go/lambda.NewHandler.func1\n\t/home/sarvs/go/pkg/mod/github.com/aws/aws-lambda-go#v1.22.0/lambda/handler.go:124\ngithub.com/aws/aws-lambda-go/lambda.lambdaHandler.Invoke\n\t/home/sarvs/go/pkg/mod/github.com/aws/aws-lambda-go#v1.22.0/lambda/handler.go:24\ngithub.com/aws/aws-lambda-go/lambda.(*Function).Invoke\n\t/home/sarvs/go/pkg/mod/github.com/aws/aws-lambda-go#v1.22.0/lambda/function.go:64\nreflect.Value.call\n\t/snap/go/7013/src/reflect/value.go:476\nreflect.Value.Call\n\t/snap/go/7013/src/reflect/value.go:337\nnet/rpc.(*service).call\n\t/snap/go/7013/src/net/rpc/server.go:377"
}

How to recursively delete objects

I would like to delete all .JPEG files from specified path at S3 bucket. For example, lets say that I have structure on S3 cloud service similar to following:
Obj1/
Obj2/
Obj3/
image_1.jpeg
...
image_N.jpeg
Is it possible to specify Obj1/Obj2/Obj3 as DeleteObjectsInput's prefix and recursively delete all .JPEG files that contain such prefix.
Here is my code:
func (s3Obj S3) Delete() error {
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(s3Obj.Region),
}))
svc := s3.New(sess)
input := &s3.DeleteObjectsInput{
Bucket: aws.String(s3Obj.Bucket),
Delete: &s3.Delete{
Objects: []*s3.ObjectIdentifier{
{
Key: aws.String(s3Obj.ItemPath),
},
},
Quiet: aws.Bool(false),
},
}
result, err := svc.DeleteObjects(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
glog.Errorf("Error occurred while trying to delete object from S3. Error message - %v", aerr.Error())
}
} else {
glog.Errorf("Error occurred while trying to delete object from S3. Error message - %v", err.Error())
}
return err
}
glog.Info(result)
return nil
}
sObj3.ItemPath represents Obj1/Obj2/Obj3 path from example above. As a result of this function I do not get any error. I actually get the following message:
Deleted: [{
Key: "Obj1/Obj2/Obj3"
}]
But when I check my S3 cloud service, nothing is done. What am I doing wrong?
EDIT
I've changed my code so my Delete function accepts list of objects from which I make a list of s3.ObjectIdentifier. There is roughly 50 .JPEG files in that list, and for some reason following code ONLY DELETES LAST ONE. I am not sure why.
func (s3Obj S3) Delete(objects []string) error {
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(s3Obj.Region),
}))
svc := s3.New(sess)
var objKeys = make([]*s3.ObjectIdentifier, len(objects))
for i, v := range objects {
glog.Info("About to delete: ", v)
objKeys[i] = &s3.ObjectIdentifier{
Key: &v,
}
}
input := &s3.DeleteObjectsInput{
Bucket: aws.String(s3Obj.Bucket),
Delete: &s3.Delete{
Objects: objKeys,
Quiet: aws.Bool(false),
},
}
result, err := svc.DeleteObjects(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
glog.Errorf("Error occurred while trying to delete object from S3. Error message - %v", aerr.Error())
}
} else {
glog.Errorf("Error occurred while trying to delete object from S3. Error message - %v", err.Error())
}
return err
}
glog.Info(result)
return nil
}

How to write unit test for http request in golang?

I don't know how to test the http response given in the code below.
func getVolDetails(volName string, obj interface{}) error {
addr := os.Getenv("MAPI_ADDR")
if addr == "" {
err := errors.New("MAPI_ADDR environment variable not set")
fmt.Println(err)
return err
}
url := addr + "/path/to/somepage/" + volName
client := &http.Client{
Timeout: timeout,
}
resp, err := client.Get(url)
if resp != nil {
if resp.StatusCode == 500 {
fmt.Printf("VSM %s not found\n", volName)
return err
} else if resp.StatusCode == 503 {
fmt.Println("server not reachable")
return err
}
} else {
fmt.Println("server not reachable")
return err
}
if err != nil {
fmt.Println(err)
return err
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(obj)
}
With the help of some references i wrote unit test for this which is given below
func TestGetVolDetails(t *testing.T) {
var (
volume v1.Volume
server *httptest.Server
)
tests := map[string]struct {
volumeName string
err error
}{
"TestOne": {"vol", nil},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
response := `{"metadata":{"annotations":{"vsm.openebs.io/targetportals":"10.98.65.136:3260","vsm.openebs.io/cluster-i ps":"10.98.65.136","openebs.io/jiva-iqn":"iqn.2016-09.com.openebs.jiva:vol","deployment.kubernetes.io/revision":"1","openebs.io/storage-pool" :"default","vsm.openebs.io/replica-count":"1","openebs.io/jiva-controller-status":"Running","openebs.io/volume-monitor":"false","openebs.io/r eplica-container-status":"Running","openebs.io/jiva-controller-cluster-ip":"10.98.65.136","openebs.io/jiva-replica-status":"Running","vsm.ope nebs.io/iqn":"iqn.2016-09.com.openebs.jiva:vol","openebs.io/capacity":"2G","openebs.io/jiva-controller-ips":"10.36.0.6","openebs.io/jiva-repl ica-ips":"10.36.0.7","vsm.openebs.io/replica-status":"Running","vsm.openebs.io/controller-status":"Running","openebs.io/controller-container- status":"Running","vsm.openebs.io/replica-ips":"10.36.0.7","openebs.io/jiva-target-portal":"10.98.65.136:3260","openebs.io/volume-type":"jiva ","openebs.io/jiva-replica-count":"1","vsm.openebs.io/volume-size":"2G","vsm.openebs.io/controller-ips":"10.36.0.6"},"creationTimestamp":null ,"labels":{},"name":"vol"},"status":{"Message":"","Phase":"Running","Reason":""}}`
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, response)
}))
os.Setenv("MAPI_ADDR", "http://"+server.URL)
if got := GetVolDetails(tt.volumeName, &volume); got != tt.err {
t.Fatalf("GetVolDetails(%v) => got %v, want %v ", tt.volumeName, got, tt.err)
}
defer server.Close()
})
}
}
Where response is the response i'm getting from the server. This gives me always different errors.
got invalid character '<' looking for beginning of value, want <nil>
got Get http://www.HugeDomains.com: net/http: request canceled (Client.Timeout exceeded while awaiting headers), want <nil>
What am I doing wrong?
Edit:
Updated the code with SOME_ADDR to MAPI_ADDR which was done while posting question. Please don't be confused with that, problem remains as it is.
You are getting a timeout but you are not specifying what timeout is set to. I suspect that this is not a time.Duration object and that is causing your timeout. There are a few other issues as well. To get this to work I did:
Change the function being called in the test to getVolDetails to match the code (not the lower case g)
Set the Timeout when creating the client to Timeout: time.Second * 10
Remove the "http://"+ from the os.Setenv("MAPI_ADDR", "http://"+server.URL) line
Corrected code is:
var timeout time.Duration = time.Second * 1000
func getVolDetails(volName string, obj interface{}) error {
addr := os.Getenv("MAPI_ADDR")
if addr == "" {
err := errors.New("MAPI_ADDR environment variable not set")
fmt.Println(err)
return err
}
url := addr + "/path/to/somepage/" + volName
client := &http.Client{
Timeout: timeout,
}
resp, err := client.Get(url)
if resp != nil {
if resp.StatusCode == 500 {
fmt.Printf("VSM %s not found\n", volName)
return err
} else if resp.StatusCode == 503 {
fmt.Println("server not reachable")
return err
}
} else {
fmt.Println("server not reachable")
return err
}
if err != nil {
fmt.Println(err)
return err
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(obj)
}
and test:
func TestGetVolDetails(t *testing.T) {
var (
volume v1.Volume
server *httptest.Server
)
tests := map[string]struct {
volumeName string
err error
}{
"TestOne": {"vol", nil},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
response := `{"metadata":{"annotations":{"vsm.openebs.io/targetportals":"10.98.65.136:3260","vsm.openebs.io/cluster-i ps":"10.98.65.136","openebs.io/jiva-iqn":"iqn.2016-09.com.openebs.jiva:vol","deployment.kubernetes.io/revision":"1","openebs.io/storage-pool" :"default","vsm.openebs.io/replica-count":"1","openebs.io/jiva-controller-status":"Running","openebs.io/volume-monitor":"false","openebs.io/r eplica-container-status":"Running","openebs.io/jiva-controller-cluster-ip":"10.98.65.136","openebs.io/jiva-replica-status":"Running","vsm.ope nebs.io/iqn":"iqn.2016-09.com.openebs.jiva:vol","openebs.io/capacity":"2G","openebs.io/jiva-controller-ips":"10.36.0.6","openebs.io/jiva-repl ica-ips":"10.36.0.7","vsm.openebs.io/replica-status":"Running","vsm.openebs.io/controller-status":"Running","openebs.io/controller-container- status":"Running","vsm.openebs.io/replica-ips":"10.36.0.7","openebs.io/jiva-target-portal":"10.98.65.136:3260","openebs.io/volume-type":"jiva ","openebs.io/jiva-replica-count":"1","vsm.openebs.io/volume-size":"2G","vsm.openebs.io/controller-ips":"10.36.0.6"},"creationTimestamp":null ,"labels":{},"name":"vol"},"status":{"Message":"","Phase":"Running","Reason":""}}`
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, response)
}))
os.Setenv("MAPI_ADDR", server.URL)
if got := getVolDetails(tt.volumeName, &volume); got != tt.err {
t.Fatalf("GetVolDetails(%v) => got %v, want %v ", tt.volumeName, got, tt.err)
}
defer server.Close()
})
}
}

How to do unit testing of HTTP requests using Ginkgo?

i have just started learning to write unit tests for the http requests, i went through several blogs but i didn't understood how to write tests for this using Ginkgo.
func getVolDetails(volName string, obj interface{}) error {
addr := os.Getenv("SOME_ADDR")
if addr == "" {
err := errors.New("SOME_ADDR environment variable not set")
fmt.Println(err)
return err
}
url := addr + "/path/to/somepage/" + volName
client := &http.Client{
Timeout: timeout,
}
resp, err := client.Get(url)
if resp != nil {
if resp.StatusCode == 500 {
fmt.Printf("VSM %s not found\n", volName)
return err
} else if resp.StatusCode == 503 {
fmt.Println("server not reachable")
return err
}
} else {
fmt.Println("server not reachable")
return err
}
if err != nil {
fmt.Println(err)
return err
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(obj)
}
// GetVolAnnotations gets annotations of volume
func GetVolAnnotations(volName string) (*Annotations, error) {
var volume Volume
var annotations Annotations
err := getVolDetails(volName, &volume)
if err != nil || volume.Metadata.Annotations == nil {
if volume.Status.Reason == "pending" {
fmt.Println("VSM status Unknown to server")
}
return nil, err
}
// Skipped some part,not required
}
I went through this blog and it exactly explains what my code requires but it uses Testing package and i want to implement this using ginkgo.
Take a look at ghttp package:
http://onsi.github.io/gomega/#ghttp-testing-http-clients
https://godoc.org/github.com/onsi/gomega/ghttp
A rough sketch might look like:
import (
"os"
. "github.com/onsi/ginkgo/tmp"
"github.com/onsi/gomega/ghttp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("GetVolAnnotations", func() {
var server *ghttp.Server
var returnedVolume Volume
var statusCode int
BeforeEach(func() {
server = ghttp.NewServer()
os.Setenv("SOME_ADDR", server.Addr())
server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/path/to/somepage/VOLUME"),
ghttp.RespondWithJSONEncodedPtr(&statusCode, &returnedVolume),
)
)
})
AfterEach(func() {
server.Close()
})
Context("When when the server returns a volume", func() {
BeforeEach(func() {
returnedVolume = Volume{
Metadata: Metadata{
Annotations: []string{"foo"}
}
}
statusCode = 200
})
It("returns the annotations associated with the volume", func() {
Expect(GetVolAnnotations("VOLUME")).To(Equal([]string{"foo"}))
})
})
Context("when the server returns 500", func() {
BeforEach(func() {
statusCode = 500
})
It("errors", func() {
value, err := GetVolAnnotations("VOLUME")
Expect(value).To(BeNil())
Expect(err).To(HaveOccurred())
})
})
Context("when the server returns 503", func() {
BeforEach(func() {
statusCode = 503
})
It("errors", func() {
value, err := GetVolAnnotations("VOLUME")
Expect(value).To(BeNil())
Expect(err).To(HaveOccurred())
})
})
})
I think you've got a few issues with your code though. If you get a 500 or 503 status code you won't necessarily have an err so you'll need to create and send back a custom error from your server.