googlecloudplatform / berglas Goto Github PK
View Code? Open in Web Editor NEWA tool for managing secrets on Google Cloud
Home Page: https://cloud.google.com/secret-manager
License: Apache License 2.0
A tool for managing secrets on Google Cloud
Home Page: https://cloud.google.com/secret-manager
License: Apache License 2.0
Steps to reproduce
➜ project-x git:(master) ✗ berglas create gs://<berglas-bucket>/database-username jonny \
--key projects/<project-id>/locations/global/keyRings/<key-ring>/cryptoKeys/<key-name>
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x152db8b]
goroutine 1 [running]:
github.com/GoogleCloudPlatform/berglas/pkg/berglas.secretFromAttrs(...)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/berglas.go:123
github.com/GoogleCloudPlatform/berglas/pkg/berglas.(*Client).encryptAndWrite(0xc0002e2000, 0x17ef480, 0xc0001aa9c0, 0x7ffeefbff944, 0x14, 0x7ffeefbff959, 0x24, 0x7ffeefbff98d, 0x4e, 0xc0001a2610, ...)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/writer.go:110 +0x96b
github.com/GoogleCloudPlatform/berglas/pkg/berglas.(*Client).Create(0xc0002e2000, 0x17ef480, 0xc0001aa9c0, 0xc00022bcc8, 0x1, 0xc0002e2000, 0x0)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/create.go:75 +0xe7
github.com/GoogleCloudPlatform/berglas/pkg/berglas.Create(0x17ef480, 0xc0001aa9c0, 0xc00022bcc8, 0x8, 0x8, 0x0)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/pkg/berglas/create.go:30 +0xa2
main.createRun(0x1c25fe0, 0xc0001aa980, 0x2, 0x4, 0x0, 0x0)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/main.go:500 +0x285
github.com/spf13/cobra.(*Command).execute(0x1c25fe0, 0xc0001aa940, 0x4, 0x4, 0x1c25fe0, 0xc0001aa940)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/pkg/mod/github.com/spf13/[email protected]/command.go:826 +0x460
github.com/spf13/cobra.(*Command).ExecuteC(0x1c25360, 0x1c2ef20, 0x1708409, 0x3)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/pkg/mod/github.com/spf13/[email protected]/command.go:914 +0x2fb
github.com/spf13/cobra.(*Command).Execute(...)
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/pkg/mod/github.com/spf13/[email protected]/command.go:864
main.main()
/private/tmp/berglas-20191013-53234-k2zn8c/berglas-0.2.1/src/github.com/GoogleCloudPlatform/berglas/main.go:422 +0xb88
Possible Causes
I get a panic error most likely because whenever attempting to write to the bucket I don't have necessary permissions. This is most likely due to the fact that there are two error branches that are not being checked
https://github.com/GoogleCloudPlatform/berglas/blob/master/pkg/berglas/writer.go#L97-L107
if terr, ok := err.(*googleapi.Error); ok {
switch terr.Code {
case http.StatusNotFound:
return nil, errors.New("bucket does not exist")
case http.StatusPreconditionFailed:
if conds.DoesNotExist {
return nil, errSecretAlreadyExists
}
return nil, errSecretModified
/** default: // other error codes are not being checked */
}
} /** else { // Non-google error is not checked } */
This may be related to #40, I'm not sure. Regardless, I'm experiencing the following:
berglas grant
berglas create
to overwrite the existing key/cert with the new ones)When an object already exists and I have the permissions to overwrite it with a new version I would expect the IAM permissions created as a result of the prior berglas grant
call to be retained.
If this is an explicit expectation of create
for security purposes or similar I would expect the edit
functionality described in #40 to retain grants (I didn't manage to spot anything in the modifications of that PR that does this).
Or have I somehow managed to create a completely barmy GCS bucket that is behaving in an unexpected way? I tested using gsutil cp
and verified that that is also not retaining the object permissions or metadata when a version of the object already exists, which surprised me.
It would be awesome to have support for deployments with:
envFrom:
- secretRef:
name: berglas://bucket/foo
where bucket/foo
is a file such as:
FOO=QkFSCg==
which is specially useful for deployments with hundreds of secret envs. Defining one env:
per secret would be cumbersome.
Being able to just wget some url to get berglas would be useful.
Hi Team,
Cloud Run examples include step
- Grant the service account access to read the Cloud Run deployment's environment variables:
Could you clarify why this is needed by Cloud Run? (I initially asked on the alpha-testers forum, but they suggested I'd ask here instead).
The reason I'm asking is, we'd like to limit the permissions for the Cloud Run SA as much as possible. However, when I attempt to grant this SA run.viewer
role only on the service it is assigned to, then we run into an issue where the very first deployment of a service fails, because Berglas is unable to read its own service's env vars (since we can't grant the role until we deploy the service). We then grant it this role on the service, and have to re-deploy the service once again to make it work.
Compare this e.g. to Cloud Functions, where env vars are automatically "passed" to the runtime, without having to grant any additional roles to read them (so a GCF SA could have literally 0 permissions if desired).
Thanks!
On the description says
cli: also allow berlgas:// prefixes , BERLGAS??????? its BERLGAS or BERGLAS?
UI support would be awesome. Each user can deploy into either GAE or GKE.
can anyone give a non programmer like me instructions on how to use Berglas to startup wordpress
i'm looking at these directions:
First, we set the credentials to access to the database through environment variables (we use PHP function getenv):
define( 'DB_NAME', getenv('DB_NAME') );
/** MySQL database username */
define( 'DB_USER', getenv('DB_USER') );
/** MySQL database password */
define( 'DB_PASSWORD', getenv('DB_PASSWORD') );
/** MySQL hostname */
define( 'DB_HOST', getenv('DB_HOST') );
It would be correct to pass this sensitive data through secrets but they are not (currently) natively supported by Cloud Run: for the sake of simplicity we will just pass them as plain-text but for production deploy it is absolutely recommended to use one of the possible workarounds available here https://www.sethvargo.com/secrets-in-serverless/.
I followed https://github.com/GoogleCloudPlatform/berglas/tree/master/examples/kubernetes to setup berglas for my k8s cluster, and it seems working fine.
Now, I am thinking about access control for berglas-secrets-webhook. In my understanding, cloudfunction is public. Do you have any plans to support access control or do you think there is no risk even if it is public or do you already have any access controls?
not clear how to explicitly specify a GCP region when creating/bootstrapping a berglas bucket
Hi,
I'm trying to deploy the go example on Cloudrun on GKE and I'm getting this error :
panic: failed to resolve environment variables: failed to find environment variables: failed to communicate with cloud run: {
"error": {
"code": 403,
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED"
}
The only command that is different from the README is the gcloud deploy command :
gcloud beta run deploy berglas-example-go \
--project ${PROJECT_ID} \
--platform gke \
--namespace knative-serving \
--cluster my-cluster \
--region europe-west4 \
--image gcr.io/${PROJECT_ID}/berglas-example-go:0.0.1 \
--memory 1G \
--concurrency 10 \
--set-env-vars "API_KEY=berglas://${BUCKET_ID}/api-key,TLS_KEY=berglas://${BUCKET_ID}/tls-key?destination=tempfile"
Not that I had to remove the --allow-unauthenticated
flag from the deploy command as it is not supported on GKE.
panic: /debug/requests is already registered. You may have two independent copies of golang.org/x/net/trace in your binary, trying to maintain separate state. This may involve a vendored copy of golang.org/x/net/trace.
goroutine 1 [running]:
golang.org/x/net/trace.init.0()
/data/develop/go/goprojects/src/golang.org/x/net/trace/trace.go:123
+0x428
This happen to me when i try to use berglas with other google lib to access the IAM api.
Hi - I'm running a Rails app on GAE Flexible - Ruby. I'd prefer not to write my own Dockerfile just so I can use Berglas. Is there any way to use Berglas with GAE Flexible - Ruby out of the box, without writing a Dockerfile?
Hi,
I'm trying to get some things working with berglas, but in my organization policy it is stated that ACLs aren't allowed anymore, just IAM on buckets (see https://cloud.google.com/storage/docs/bucket-policy-only)
The documentation of berglas talks about IAM as well, but it seems like when I'm trying to give my own account (which is owner on the project) read permissions, it failes with the following error message:
$ berglas grant berglas-goingontheroad-nl/wordpress-db-user --member [email protected]
failed to get Storage IAM policy: googleapi: Error 400: Object policies are disabled for bucket 'berglas-goingontheroad-nl' when Bucket Policy Only is enabled. Read more at https://cloud.google.com/storage/docs/bucket-policy-only., invalid
Is this a bug, or is it intentional that berglas requires per object ACLs?
Thanks,
Wietse
Hi there,
Just a heads-up that trying to follow the download instructions that reads:
This will download the latest version built against the master branch. To download a specific version, specify a git tag in place of "master" in the URL.
Always gives me the 0.1.0
version.
Tried:
# tag 0.1.2
$ curl -O https://storage.googleapis.com/berglas/0.1.2/darwin_amd64/berglas
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12.7M 100 12.7M 0 0 4467k 0 0:00:02 0:00:02 --:--:-- 4468k
$ chmod +x berglas
$ ./berglas version
0.1.0
# master
$ curl -O https://storage.googleapis.com/berglas/master/darwin_amd64/berglas
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12.7M 100 12.7M 0 0 5368k 0 0:00:02 0:00:02 --:--:-- 5368k
$ chmod +x berglas
$ ./berglas version
0.1.0
Hope I'm not missing something and just creating noise.
Best regards,
Rafa
I gave access to the SA as per the example and it was working fine, meaning able to get the secret using berglas access ${BUCKET_ID}/foo
Now, when I revoke the access for the same SA and again try to get the secret, I am able to get the response, which should not be the case and should have been a Permission Denied error.
Also, if there is no access defined, meaning when I put the secret and try to access it I get the unencrypted access. Shouldn't the secret be always protected and only accessible by the SA or member whom we add using the berglas grant ${BUCKET_ID}/foo --member *
command ?
berglas bootstrap --project $PROJECT_ID --bucket $BUCKET_ID
failed to create KMS key ring berglas: rpc error: code = FailedPrecondition desc = Google Cloud KMS API has not been used in this project before, or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudkms.googleapis.com/overview?project=1075231961184 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
This bucket will be used to store the secret and the project can have multiple buckets.
There should be a capability to add labels like owner:name, classification: confidential to easily distinguished between the buckets to get a report.
It looks like the current implementation handles berglas env variable references.
It would be nice to be able to mount K8S secret volumes that reference berglas secrets. Not 100% sure how it work - but perhaps if the opaque secret starts with berglass:// it indicates that the actual value should be pulled from berglas?
When I try to test berglas on windows machine, it can't save a decrypted secret into file.
$ echo %VAR%
berglas://my-bucket/my-secret?destination=tempfile
$ cat echo-var.bat
@echo %VAR%
berglas exec --local -- echo-var.bat
failed to chmod filepath C:\Users\xakep\AppData\Local\Temp\berglas-901227331: chmod C:\Users\xakep\AppData\Local\Temp\berglas-901227331: not supported by windows
Maybe this error should be ignored on Windows letting the process to continue?
Or maybe it's not secure to leave default file attributes.. But I think berglas is not intended to be used on Windows in production, so ignore chmod error is better than just not work at all.
Hi,
I've been trying to use berglas on a Container-Optimized OS but it fails to detect the runtime, is that by design or is this unexpected?
While examining my docker logs for the container, I see the following error message:
failed to detect runtime environment: unknown runtime
It's related to this code which made me wonder if it's design or not.
Or should --local flag be used for Container-Optimized OS as it looks like I could not spot a reliable way to identify the runtime for it other than talking to the metadata service.
Thanks!
Are there any plans to extend support to other runtimes (Python or Node)?
(I'm working on the fix)
Hey @sethvargo
I'm looking to use a version with a80844e.. Can I please get a new version (or an alternate way to download a binary with that commit? - I did check https://storage.googleapis.com/berglas/a80844e0e4dff34f767bf12adb17d56330f79168/linux_amd64/berglas which didn't work)
Thanks!
Passing secrets as environment variables is a deprecated pattern for sensitive information (https://www.sethvargo.com/secrets-in-serverless/ or https://github.com/ahmetb/cloud-run-faq#how-to-configure-secrets-for-cloud-run-applications). However, berglas
offers a sub-command exec
which decrypts keys from the bucket and makes those available as environment variables to the child application:
Lines 711 to 715 in d9641d9
This seems to suffer from the same drawbacks as having secrets in plain text environment variables. Is my understanding correct about this? If so, I think it would be better if the documentation for berglas exec
would point out that this is no water-proof approach.
Spec:
Update the contents of a secret by reading the encrypted data from Google
Cloud Storage, decrypting it with Google Cloud KMS, editing it in-place using an editor,
encrypting the updated content using Google Cloud KMS, writing it back into Google
Cloud Storage. The file MUST be saved and editor MUST exit with exit code 0 for the
secret to update.
Usage:
berglas edit [secret] [flags]
Examples:
# Edit a secret named "api-key" from the bucket "my-secrets"
berglas edit my-secrets/api-key
Flags:
--editor the command to open a new editor. If this flag is not specified,
it defaults to reading env vars `VISUAL`, or `EDITOR` (in that order).
If neither environment variable is found, these commands are attempted:
`vi`, `emacs`, `nano`, `pico`.
The command is invoked with just one argument: a temporary filename
with contents of the secret. The command MUST exit with code 0.
-h, --help help for edit
There is some assumption about file contents here (that they are editable using an editor and is not, say, a pdf file). However, by using the --editor
flag you can specify, for example, Acrobat Pro for pdf, your choice of editor that can handle the file contents.
If this command exists, I would also recommend changing create
so it doesn't silently overwrite, but fails with error, and you have to use the edit command to update secrets.
Thanks very much for Berglas. I was very excited to find a native Go option for secret management.
I'm having a hard time figuring out how to set sufficient scopes for my service account to read secrets. I'm using berglas.Replace
. The error I'm getting (mildly redacted) is:
failed to access secret BUCKET/SECRET: failed to access secret: failed to decrypt dek: rpc error: code = PermissionDenied desc = Request had insufficient authentication scopes.
I don't see anything documented about what permissions the service account needs (or for that matter, how to provide them). I gave it IAM roles Storage Object Viewer
and Cloud KMS CryptoKey Decrypter
.
Apologies for what is definitely a naive and possibly also a stupid question. Thanks.
I did setup my kubernetes cluster following https://github.com/GoogleCloudPlatform/berglas/tree/master/examples/kubernetes.
It seems working fine for usual pods.
But, berglas does not work well for daemonsets becasuse of either MutatingWebhookConfiguration or because sidecar does not start for daemonset.
Could you tell me how to use berglas with daemonset? I want to use datadog-agent https://docs.datadoghq.com/agent/kubernetes/daemonset_setup/?tab=k8sfile#create-manifest and want to use berglas for DD_API_KEY
.
The README states that "Berglas is not an officially supported Google product" but could it be clarified whether Berglas is still subject to Google's usual internal security measures (e.g. secure builds, code security, reviews, etc)?
Thanks!
I tried to bootstrap a new setup. Then I got an error that the kms rotation period is not correct.
$ git rev-parse HEAD
d6b103a70c7b62989864d1dfec36213bf99eaa0c
$ GO111MODULE=on go run main.go bootstrap --project $PROJECT_ID --bucket $BUCKET_ID
failed to create KMS crypto key berglas-key: rpc error: code = InvalidArgument desc = Invalid rotation period.
exit status 1
The same happens with the latest available binary.
Any ideas?
I've set up Berglas as well as the various IAM settings outlined in the Flex example README (using the flex service account), but when deploying I still get the following error:
failed to access secret BUCKET_ID/my-secret: failed to access secret: failed to decrypt dek: rpc error: code = PermissionDenied desc = Permission 'cloudkms.cryptoKeyVersions.useToDecrypt' denied for resource 'projects/MY_PROJECT/locations/global/keyRings/my_key_ring/cryptoKeys/my_key'.
I've issued the gcloud kms keys add-iam-policy-binding
command with --member service-PROJECT_NUMBER@gae-api-prod.google.com.iam.gserviceaccount.com
assigned to the role --role roles/cloudkms.cryptoKeyEncrypterDecrypter
, but still to no avail.
Any ideas or insights? Thanks!
Hello,
does it makes sense to update official GCP documentation?
https://cloud.google.com/functions/docs/env-var#managing_secrets
Provide a way to output in JSON or YAML for scripting and automation.
Hi,
I run into an issue when using berglas locally with berglas exec --local
. It seems a newline character is added to the decrypted environment variable, which isn't a part of the originally encrypted secret.
Here is a detailed walkthrough of my testing with this, and a reproduction path:
$ echo 'testsecretwithoutnewline' | berglas create berglas-wietse/testsecret - --key projects/berglas-wietse/locations/global/keyRings/berglas/cryptoKeys/berglas-key
Successfully created secret [testsecret] with generation [1569245517544173]
$ berglas access berglas-wietse/testsecret
testsecretwithoutnewline
$ TESTENV=$(berglas access berglas-wietse/testsecret)
$ echo "ONE${TESTENV}TWO"
ONEtestsecretwithoutnewlineTWO
$ export TESTENV=berglas://berglas-wietse/testsecret
$ berglas exec --local ${SHELL}
$ echo "ONE${TESTENV}TWO"
ONEtestsecretwithoutnewline
TWO
As you can see, in the berglas exec environment, a newline at the end of the secret is suddenly added.
Hi,
First, thanks for this awesome tool !
I got an issue when I revoke access to a user on a given secret.
If this user has been granted access to others secrets we got a permission denied on KMS decrypt resource.
Here what I try
berglas create sku-berglas_secrets/sku/test/secret1 1234 --key projects/sku-berglas/locations/global/keyRings/berglas/cryptoKeys/berglas-key
berglas create sku-berglas_secrets/sku/test/secret2 5678 --key projects/sku-berglas/locations/global/keyRings/berglas/cryptoKeys/berglas-key
berglas grant sku-berglas_secrets/sku/test/secret1 --member serviceAccount:[email protected]
berglas grant sku-berglas_secrets/sku/test/secret2 --member serviceAccount:[email protected]
secret2
berglas revoke sku-berglas_secrets/sku/test/secret2 --member serviceAccount:[email protected]
secret1
berglas access sku-berglas_secrets/sku/test/secret1
I've got the following error
failed to access secret: failed to decrypt dek: rpc error: code = PermissionDenied desc = Permission 'cloudkms.cryptoKeyVersions.useToDecrypt' denied on resource 'projects/proximis-berglas/locations/global/keyRings/berglas/cryptoKeys/berglas-key' (or it may not exist).
I look into code and in GCP console, and what I understand :
berglas revoke
operation will remove the role roles/cloudkms.cryptoKeyDecrypter
for the given user but it doesn't take care if the same user has other granted secrets.
Cobra has a builtin generator to create completion scripts for bash
and zsh
. Many projects make use of this generator, among others sigs.k8s.io/krew, k8s.io/minikube, or GoogleContainerTools/skaffold. This is usually used as source <(berglas completion zsh)
in your shell, which then offers an improved CLI experience -- especially for new and casual users.
Is there a particular reason why berglas
does not want that?
After downloading the Linux binary I had to chmod +x
so it would run.
Maybe it should be mentioned in the README.
--format 'value(status.address.url)')
is the new way to read the URL of service in Knative v1 API.
Some systems like Istio will not make networking available during the first few milliseconds (istio/istio#9454).
Therefore a code path executed (i.e. pkg auto) in initialization of a program is likely to fail using networking on Istio (especially more prevalent in "fast" languages like Go where process/runtime start overhead is low).
It would be great to say Berglas to retry N times with M ms intervals.
It does not always happen, but on CI I sometimes get this error when using berglas with another app(in this case, terraform) with spawning a child process.
resource "berglas_secret" "foo" {
data = "my-secret-data"
uri = "gs://bucket/path"
key = "projects/PROJECT_ID/locations/global/keyRings/berglas/cryptoKeys/berglas-key"
}
"Get the Cloud Run service account email" is assuming the default compute service account is used as service account of the cloud run service.
Users can customize it, it is actually recommended that they do.
You should instead describe the service and extract the service account
This seems like it should work just like Cloud Run, except it just hasn't been done yet - is that correct? If so, I can take this on..
Add verbose mode for debugging purposes
This is a great tool, and we're evaluating using it as a config manager (a la Heroku). The one feature that's missing is the ability to rollback easily by providing versioning. We can easily piggyback on GCS's versioning scheme that generates a new generation every time you change an object in a bucket that has versioning enabled. The access
command could provide an additional flag which would return previous version of the object. The exec
command could do that as well, or just use latest version - which is fine in most cases.
I'm doing
import _ "github.com/GoogleCloudPlatform/berglas/pkg/auto"
in my Go app and it starts/boots just fine (on Kubernetes, or on Cloud Run), only later I find out it actually printed some log lines with errors about secrets initialization.
As a user I expect app to crash ASAP as there's no point of moving the app forward if a requirement cannot be initialized. It's certain that app will crash, and crashing early is a very conventional readiness/health check (recognized by runtimes like Kubernetes or Cloud Run).
Most CLIs accept --options before positional args:
But this doesn't seem to work
berglas create --key $KEY my-secret/CONSUMER_KEY xxx
Error: accepts 2 arg(s), received 3
Usage:
...
hello! thanks for this library. I'm trying to speed up my development cycles and obviously its slow to rebuild/re-deploy to make sure everything works.
i was hoping to run locally before deploying to Cloud Run. However i get this error when i try
2019/08/30 20:48:52 failed to detect environment: unknown runtime
panic: failed to detect environment: unknown runtime
goroutine 1 [running]:
github.com/GoogleCloudPlatform/berglas/pkg/auto.handleError(...)
/src/vendor/github.com/GoogleCloudPlatform/berglas/pkg/auto/importer.go:108
github.com/GoogleCloudPlatform/berglas/pkg/auto.init.0()
/src/vendor/github.com/GoogleCloudPlatform/berglas/pkg/auto/importer.go:44 +0x64e
its the same error whether i run using a container or locally and it's the auto package. If i comment that import out everything works locally (sort of).
there isn't any documentation about local run vs deployed run. would be awesome to have that. for now i'm going to just do the wrong thing with env vars in a cloud function...
i am running on macOS with docker for Mac and go 1.12 otherwise.
thanks again!
I followed the node.js & Cloud Run example you have here and the resultant image was 300+MBs. Switching to node:10-alpine
I than ran into this issue on deployment
failed to find environment variables: failed to execute cloud run request: Get https://us-central1-run.googleapis.com/apis/serving.knative.dev/v1alpha1/namespaces/project-id/revisions/service-name-00015: x509: certificate signed by unknown authority
Here is the Dockerfile
FROM node:10-alpine
ENV NODE_ENV=production
WORKDIR /urs/src/app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . ./
COPY --from=gcr.io/berglas/berglas:latest /bin/berglas /bin/berglas
ENTRYPOINT exec /bin/berglas exec -- yarn start
I expected this to work without me needing to add ca-certificates
as a package to the Docker image as it is contained within the Berglas image.
adding RUN apk add ca-certificates
to my Dockerfile solved the issue and I get an image around 30MBs in size 🎉
Full example code here: https://github.com/jthegedus/firebase-gcp-examples/tree/master/gcp-cloudrun-berglas/helloService
Are my assumptions incorrect here, or is this a bug with Berglas?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.