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
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
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"
}
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
}
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()
})
}
}
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.