Skip to content

Commit

Permalink
premain: enable JSON formatted logs if EDG_LOG_FORMAT=json (#766)
Browse files Browse the repository at this point in the history
* marble-injector: fix incorrect log level for error messages
* premain: enable JSON formatted logs if env var is set
* Document EDG_LOG_FORMAT variable

---------

Signed-off-by: Daniel Weiße <[email protected]>
  • Loading branch information
daniel-weisse authored Nov 20, 2024
1 parent 545d5f1 commit 82ce121
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 8 deletions.
20 changes: 19 additions & 1 deletion cmd/premain-libos/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import (
"path/filepath"
"strings"

"github.com/edgelesssys/marblerun/internal/constants"
"github.com/edgelesssys/marblerun/marble/premain"
marblePremain "github.com/edgelesssys/marblerun/marble/premain"
"github.com/edgelesssys/marblerun/util"
"github.com/spf13/afero"
"golang.org/x/sys/unix"
)
Expand All @@ -26,7 +29,9 @@ const (
occlum
)

func exit(format string, args ...interface{}) {
var exit func(format string, args ...interface{})

func exitStdLog(format string, args ...interface{}) {
// Print error message in red and append newline
// then exit with error code 1
msg := fmt.Sprintf("Error: %s\n", format)
Expand All @@ -35,6 +40,19 @@ func exit(format string, args ...interface{}) {
}

func main() {
exit = exitStdLog
if strings.EqualFold(util.Getenv(constants.EnvLogFormat, ""), constants.LogFormatJSON) {
zapLog, err := premain.LogJSON()
if err != nil {
exit("failed to initialize logger: %s", err)
}
defer zapLog.Sync()

exit = func(format string, args ...interface{}) {
zapLog.Fatal(fmt.Sprintf(format, args...))
}
}

log.SetPrefix("[PreMain] ")

// Automatically detect libOS based on uname
Expand Down
6 changes: 4 additions & 2 deletions docs/docs/workflows/add-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Adding a service to your application requires three steps, which are described i
## **Step 1:** Get your service ready for MarbleRun

To get your service ready for MarbleRun, you need to rebuild it with one of the supported [runtimes](../features/runtimes.md):

* [EGo](../building-marbles/ego.md)
* [Edgeless RT](https://github.com/edgelesssys/marblerun/blob/master/samples/helloc%2B%2B)
* [Gramine](../building-marbles/gramine.md)
Expand All @@ -29,6 +30,7 @@ Now that your service is ready, you need to make two types of entries in the man
As is described in more detail in the [writing a manifest hands-on](../workflows/define-manifest.md#packages), the manifest contains a section `Packages`, in which allowed enclave software packages are defined.

#### EGo / EdgelessRT

To add an entry for your EGo / EdgelessRT service, run the `oesign` tool on the enclave file you built in the previous step as follows. (`oesign` is installed with [Edgeless RT](https://github.com/edgelesssys/edgelessrt).)

```bash
Expand All @@ -50,7 +52,6 @@ The tool's output is similar to the following.

To add an entry for your Gramine service, run the `gramine-sgx-get-token` tool on the `.sig` file you built in the previous step as follows. (`gramine-sgx-get-token` is installed with [Gramine](https://github.com/gramineproject/gramine/).)


```bash
gramine-sgx-get-token --sig hello.sig
```
Expand Down Expand Up @@ -91,7 +92,6 @@ ProductID (ISVPRODID) : 1
SecurityVersion (ISVSVN) : 3
```


Use `UniqueID` (i.e., `MRENCLAVE` in Intel SGX speak) or the triplet of `SignerID` (i.e., `MRSIGNER`), `SecurityVersion`, and `ProductID` to add an entry in the `Packages` section.

### **Step 2.2:** Define the parameters
Expand Down Expand Up @@ -125,6 +125,8 @@ The environment variables have the following purposes.

* `EDG_MARBLE_DNS_NAMES` is the list of DNS names and IPs the Coordinator will issue the Marble's certificate for.

Optionally, you can set the `EDG_LOG_FORMAT` environment variable to `json` to enable JSON structured logs for the Marble's startup code.

## **Step 4:** Deploy your service with Kubernetes

Typically, you'll write a Kubernetes resource definition for your service, which you'll deploy with the Kubernetes CLI, Helm, or similar tools.
Expand Down
20 changes: 15 additions & 5 deletions injector/injector.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,15 @@ func (m *Mutator) mutate(body []byte) ([]byte, error) {
marbleType, exists := pod.Labels[labelMarbleType]
if !exists {
// admission request was sent for a pod without marblerun/marbletype label, this should not happen
return m.generateResponse(pod, admReviewReq, admReviewResponse, false, fmt.Sprintf("Missing [%s] label, request denied", labelMarbleType))
msg := fmt.Sprintf("Missing [%s] label, request denied", labelMarbleType)
m.log.Error(msg)
return m.generateResponse(pod, admReviewReq, admReviewResponse, false, msg)
}
if len(marbleType) <= 0 {
// deny request if the label exists, but is empty
return m.generateResponse(pod, admReviewReq, admReviewResponse, false, fmt.Sprintf("Empty [%s] label, request denied", labelMarbleType))
msg := fmt.Sprintf("Empty [%s] label, request denied", labelMarbleType)
m.log.Error(msg)
return m.generateResponse(pod, admReviewReq, admReviewResponse, false, msg)
}

injectSgx := false
Expand Down Expand Up @@ -244,7 +248,15 @@ func (m *Mutator) mutate(body []byte) ([]byte, error) {
})
}

return m.generateResponse(pod, admReviewReq, admReviewResponse, true, fmt.Sprintf("Mutation request for pod of marble type [%s] successful", marbleType))
msg := fmt.Sprintf("Mutation request for pod of marble type [%s] successful", marbleType)
resp, err := m.generateResponse(pod, admReviewReq, admReviewResponse, true, msg)
if err != nil {
m.log.Error("Unable to mutate request: response generation failed", zap.Error(err))
return nil, err
}

m.log.Info(msg)
return resp, nil
}

// checkRequest verifies the request used was POST and not empty.
Expand Down Expand Up @@ -321,7 +333,5 @@ func (m *Mutator) generateResponse(pod corev1.Pod, request, response v1.Admissio
return nil, fmt.Errorf("unable to marshal admission response: %w", err)
}

m.log.Info(message)

return bytes, nil
}
6 changes: 6 additions & 0 deletions internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ SPDX-License-Identifier: BUSL-1.1
package constants

const (
// EnvLogFormat is the name of the environment variable used to pass the log format to the PreMain.
// Should be "json" for JSON formatted logs, or any other value for human-readable logs.
EnvLogFormat = "EDG_LOG_FORMAT"
// LogFormatJSON indicates that logs should be formatted as JSON.
LogFormatJSON = "json"

// EnvMarbleTTLSConfig is the name of the environment variable used to pass the TTLS configuration to the Marble.
EnvMarbleTTLSConfig = "MARBLE_TTLS_CONFIG"

Expand Down
20 changes: 20 additions & 0 deletions marble/premain/premain.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,26 @@ import (
"github.com/edgelesssys/marblerun/coordinator/quote/ertvalidator"
"github.com/edgelesssys/marblerun/coordinator/rpc"
"github.com/edgelesssys/marblerun/internal/constants"
"github.com/edgelesssys/marblerun/internal/logging"
"github.com/edgelesssys/marblerun/marble/config"
"github.com/edgelesssys/marblerun/util"
"github.com/google/uuid"
"github.com/spf13/afero"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)

// LogJSON replaces Go's standard logger with [*zap.Logger] to log in JSON format.
func LogJSON() (*zap.Logger, error) {
zapLogger, err := logging.New()
if err != nil {
return nil, err
}
zap.RedirectStdLog(zapLogger)
return zapLogger, nil
}

// storeUUID stores the uuid to the fs.
func storeUUID(appFs afero.Fs, marbleUUID uuid.UUID, filename string) error {
uuidBytes, err := marbleUUID.MarshalText()
Expand Down Expand Up @@ -126,6 +138,14 @@ func PreMainMock() error {
//
//nolint:revive
func PreMainEx(issuer quote.Issuer, activate ActivateFunc, hostfs, enclavefs afero.Fs) error {
if strings.EqualFold(util.Getenv(constants.EnvLogFormat, ""), constants.LogFormatJSON) {
zapLog, err := LogJSON()
if err != nil {
return err
}
defer zapLog.Sync()
}

prefixBackup := log.Prefix()
defer log.SetPrefix(prefixBackup)
log.SetPrefix("[PreMain] ")
Expand Down

0 comments on commit 82ce121

Please sign in to comment.