corneliusweig / rakkess Goto Github PK
View Code? Open in Web Editor NEWReview Access - kubectl plugin to show an access matrix for k8s server resources
License: Apache License 2.0
Review Access - kubectl plugin to show an access matrix for k8s server resources
License: Apache License 2.0
Expected behavior
Installing via Krew on an Apple M1 Mac installs rakkess.
Actual behavior
Installation errors stating the platform isn't supported:
❯ kubectl krew install access-matrix
Adding "default" plugin index from https://github.com/kubernetes-sigs/krew-index.git.
Updated the local copy of plugin index.
Installing plugin: access-matrix
W0406 15:40:51.465001 52334 install.go:164] failed to install plugin "access-matrix": plugin "access-matrix" does not offer installation for this platform
F0406 15:40:51.465066 52334 root.go:79] failed to install some plugins: [access-matrix]: plugin "access-matrix" does not offer installation for this platform
Steps To Reproduce
Steps to reproduce the behavior:
kubectl krew install access-matrix
Expected behavior
I would expect the documentation to match the binary capabilities.
Actual behavior
Some flags described in the documentation are not available in the plugin.
Steps To Reproduce
kubectl access-matrix for pod --sa cloud-controller-manager -n ccmop
It outputs the following:
Error: unknown flag: --sa
Usage:
access-matrix for <resource> [name] [flags]
Aliases:
for, resource, r
Examples:
Review access to deployments in any namespace
$ kubectl access-matrix for deployments
or
$ kubectl access-matrix resource deployments
Review access to deployments in the default namespace (with shorthands)
$ kubectl access-matrix for deploy --namespace default
Review access to deployments with custom verbs
$ kubectl access-matrix for deploy --verbs get,watch,deletecollection
Review access to a config-map with a specific name
$ kubectl access-matrix for cm config-map-name --verbs=all
Flags:
--as string Username to impersonate for the operation
--as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--cache-dir string Default cache directory (default "/home/paul/.kube/cache")
--certificate-authority string Path to a cert file for the certificate authority
--client-certificate string Path to a client certificate file for TLS
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
-h, --help help for for
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
-n, --namespace string If present, the namespace scope for this CLI request
-o, --output string output format out of (icon-table, ascii-table) (default "icon-table")
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
-s, --server string The address and port of the Kubernetes API server
--tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
--token string Bearer token for authentication to the API server
--user string The name of the kubeconfig user to use
--verbs strings show access for verbs out of (create, get, list, watch, update, patch, delete, deletecollection) (default [list,create,update,delete])
Global Flags:
-v, --verbosity string Log level (debug, info, warn, error, fatal, panic) (default "warning")
ERRO[0000] unknown flag: --sa
Context:
kubectl access-matrix version --full
rakkess: v0.4.6
platform: linux/amd64
git commit: ff2ba4f26b5fadeeef10a71e02d10acce00a94ba
build date: 2020-12-05T21:29:52Z
go version: go1.15.5
compiler: gc
Additional context
~
It is frowned upon for a package owner to submit a formula to Homebrew core formulae repository (brew submission guidelines).
So I am looking for a volunteer to submit a brew formula to homebrew-core.
This following snippet can be used as a starting point, but it has not been tested with brew audit --new-formula Formula/rakkess.rb
:
class Rakkess < Formula
desc "Show an access matrix for all kubernetes resources"
homepage "https://github.com/corneliusweig/rakkess"
url "https://github.com/corneliusweig/rakkess/archive/v0.2.0.tar.gz"
sha256 "d9b839578adb13b9ebba5f99dc1db095143ca808979dcb20973cb59e00ba55af"
head "https://github.com/corneliusweig/rakkess.git"
bottle do
# todo
end
depends_on "go" => :build
def install
ENV["GOPATH"] = HOMEBREW_CACHE/"go_cache"
(buildpath/"src/github.com/corneliusweig/rakkess").install buildpath.children
cd "src/github.com/corneliusweig/rakkess" do
system "make", "out/rakkess-darwin-amd64"
system "mv", "out/rakkess-darwin-amd64", "rakkess"
bin.install "rakkess"
# Build bash completion
system bin/"rakkess", "completion", "bash", ">", "rakkess.sh"
bash_completion.install "rakkess.sh" => "rakkess"
# Build zsh completion
system bin/"rakkess", "completion", "bash", ">", "rakkess.zsh"
zsh_completion.install "rakkess.zsh" => "_rakkess"
end
end
test do
assert_match version.to_s, shell_output("#{bin}/rakkess version")
end
end
Expected behavior:
Output on PowerShell terminals is simply monochrome and well-formatted.
Actual behavior:
Unix terminal color codes are printed in PowerShell, thus making the output unreadable.
Relates to #5
Expected behavior
rakkess version
(version is printed)
Actual behavior
a blank line is printed
Steps To Reproduce
Steps to reproduce the behavior:
with no cluster connected, but context defined, run rakkess version
version
-v debug
to show extra logging.rakkess version -v debug
DEBU[0000] Set log-level to debug
Context:
Please include the full version information: rakkess version --full
The downloaded version was v0.4.3 Darwin amd64
rakkess version --full
rakkess:
platform: darwin/amd64
git commit:
build date:
go version: go1.13.7
compiler: gc
Additional context
Add any other context about the problem here.
Currently, the help messages always show rakkess
, even if the binary is distributed for krew
. This is confusing, because in krew
the command is called access-matrix
.
When distributed standalone, call it rakkess
. When distributed for krew
, call it kubectl access-matrix
.
In release v0.5.0 and earlier, the release included binary assets, which I found helpful. However, no assets were released in v0.5.1. Please add the assets.
Also, please include builds for linux/arm64
.
Dependabot can't resolve your Go dependency files.
As a result, Dependabot couldn't update your dependencies.
The error Dependabot encountered was:
github.com/corneliusweig/rakkess/cmd: cannot find module providing package github.com/corneliusweig/rakkess/cmd
If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.
Expected behavior
Successful install
Actual behavior
kubectl krew install access_matrix
Updated the local copy of plugin index.
F1106 09:56:43.917989 62690 root.go:58] failed to load plugin "access_matrix" from the index: open /Users/mgarda/.krew/index/plugins/access_matrix.yaml: no such file or directory
Steps To Reproduce
Run:
kubectl krew install access_matrix
Context:
kubectl version
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.3", GitCommit:"5e53fd6bc17c0dec8434817e69b04a25d8ae0ff0", GitTreeState:"clean", BuildDate:"2019-06-06T01:44:30Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"darwin/amd64"}
Additional context
Add any other context about the problem here.
Expected behavior
Downloading the darwin zip from https://github.com/corneliusweig/rakkess/releases/tag/v0.4.5 and extracting should result in a binary file
Actual behavior
Binary file is missing, only the LICENSE rile is present
Steps To Reproduce
ls
shows only LICENSEContext:
Downloading and doing the same with 0.4.4 seems to still work properly.
Additional context
This is also affecting the install from krew
as krew only supports the latest version.
Typing all verbs is tedious and error-prone. For those who wish to see all verbs, there should be abbreviations such as --verbs=all
or --verbs=*
. The following should be equivalent:
rakkess --verbs=all
rakkess --verbs=create,delete,deletecollection,get,list,patch,update,watch
When trying to install rakkess via curl with:
curl -Lo rakkess.gz https://github.com/corneliusweig/rakkess/releases/download/v0.4.2/rakkess-darwin-amd64.gz && \
gunzip rakkess.gz && chmod +x rakkess && mv rakkess $GOPATH/bin/
I keep getting:
gunzip: rakkess.gz: not in gzip format
At the moment, the only output I can see from rakess
uses colour escape sequences. This doesn't display well in PowerShell, and isn't very convenient for consuming programmatically (e.g. from a GUI tool). Would you be open to a PR for an "ASCII display" flag or similar?
Sorry I do not understand this: Is it means forbidden? If so, why it not display with "no" message ?
Dependabot can't resolve your Go dependency files.
As a result, Dependabot couldn't update your dependencies.
The error Dependabot encountered was:
github.com/corneliusweig/rakkess/cmd: cannot find module providing package github.com/corneliusweig/rakkess/cmd
If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.
Awesome tool. It would be nice to have support for json output so users could use the output easily.
kubectl access-matrix for pods -o json | jq ...
Expected behavior
The latest v0.5.1 version of the rakkess/access-matrix plugin should be installable via krew.
Since they are no access-matrix-amd64-linux.tar.gz package availalble in the release page (only the source code) for this version, I reckon krew is not able to see the changes and do apply an upgrade of this plugin from v0.5.0
Actual behavior
The access-matrix-amd64-linux.tar.gz package should be available for the v0.5.1 so krew is able to upgrade the plugin installed on our boxes
Expected behavior
access-matrix should match with the command "oc who-can"
Actual behavior
access-matrix is not consistent with "oc who-can"
Steps To Reproduce
Steps to reproduce the behavior:
N/A
Context:
Rakess version:
rakkess: v0.5.0
platform: linux/amd64
git commit: e52bef1
build date: 2021-07-25T09:13:28Z
go version: go1.16.6
compiler: gc
oc client version:
oc version
Client Version: 4.11.0-0.okd-2022-08-20-022919
Kustomize Version: v4.5.4
Server Version: 4.11.0-0.okd-2022-08-20-022919
Kubernetes Version: v1.24.0-2368+b62823b40c2cb1-dirty
OKD version:
4.11.0-0.okd-2022-08-20-022919
kubectl version
Additional context
If I run the following command, you can see which groups and users can delete a secret in the namespace istio-system.
user@host: ~$ oc policy who-can delete secret
resourceaccessreviewresponse.authorization.openshift.io/<unknown>
Namespace: istio-system
Verb: delete
Resource: secrets
Users: system:admin
system:kube-controller-manager
system:serviceaccount:argocd:argocd-argocd-application-controller
system:serviceaccount:argocd:argocd-argocd-server
system:serviceaccount:argocd:argocd-operator-controller-manager
system:serviceaccount:argocd:openshift-gitops-applicationset-controller
system:serviceaccount:argocd:openshift-gitops-argocd-application-controller
system:serviceaccount:argocd:openshift-gitops-argocd-server
system:serviceaccount:cert-manager:cert-manager
system:serviceaccount:elastic-system:elastic-operator
system:serviceaccount:istio-system:istiod
system:serviceaccount:istio-system:istiod-service-account
system:serviceaccount:kube-system:generic-garbage-collector
system:serviceaccount:kube-system:namespace-controller
system:serviceaccount:kube-system:sealed-secrets-controller
system:serviceaccount:ldap-sync:ldap-sync
system:serviceaccount:openshift-apiserver-operator:openshift-apiserver-operator
system:serviceaccount:openshift-apiserver:openshift-apiserver-sa
system:serviceaccount:openshift-authentication-operator:authentication-operator
system:serviceaccount:openshift-authentication:oauth-openshift
system:serviceaccount:openshift-cloud-credential-operator:cloud-credential-operator
system:serviceaccount:openshift-cluster-storage-operator:cluster-storage-operator
system:serviceaccount:openshift-cluster-storage-operator:csi-snapshot-controller-operator
system:serviceaccount:openshift-cluster-version:default
system:serviceaccount:openshift-config-operator:openshift-config-operator
system:serviceaccount:openshift-controller-manager-operator:openshift-controller-manager-operator
system:serviceaccount:openshift-etcd-operator:etcd-operator
system:serviceaccount:openshift-etcd:installer-sa
system:serviceaccount:openshift-image-registry:cluster-image-registry-operator
system:serviceaccount:openshift-infra:service-serving-cert-controller
system:serviceaccount:openshift-infra:serviceaccount-pull-secrets-controller
system:serviceaccount:openshift-infra:template-instance-controller
system:serviceaccount:openshift-infra:template-instance-finalizer-controller
system:serviceaccount:openshift-infra:template-service-broker
system:serviceaccount:openshift-ingress-operator:ingress-operator
system:serviceaccount:openshift-kube-apiserver-operator:kube-apiserver-operator
system:serviceaccount:openshift-kube-apiserver:installer-sa
system:serviceaccount:openshift-kube-apiserver:localhost-recovery-client
system:serviceaccount:openshift-kube-controller-manager-operator:kube-controller-manager-operator
system:serviceaccount:openshift-kube-controller-manager:installer-sa
system:serviceaccount:openshift-kube-controller-manager:localhost-recovery-client
system:serviceaccount:openshift-kube-scheduler-operator:openshift-kube-scheduler-operator
system:serviceaccount:openshift-kube-scheduler:installer-sa
system:serviceaccount:openshift-kube-scheduler:localhost-recovery-client
system:serviceaccount:openshift-kube-storage-version-migrator-operator:kube-storage-version-migrator-operator
system:serviceaccount:openshift-kube-storage-version-migrator:kube-storage-version-migrator-sa
system:serviceaccount:openshift-machine-api:cluster-baremetal-operator
system:serviceaccount:openshift-machine-config-operator:default
system:serviceaccount:openshift-machine-config-operator:machine-config-controller
system:serviceaccount:openshift-monitoring:cluster-monitoring-operator
system:serviceaccount:openshift-monitoring:prometheus-operator
system:serviceaccount:openshift-network-operator:default
system:serviceaccount:openshift-oauth-apiserver:oauth-apiserver-sa
system:serviceaccount:openshift-operator-lifecycle-manager:olm-operator-serviceaccount
system:serviceaccount:openshift-operators:pgo
system:serviceaccount:openshift-service-ca-operator:service-ca-operator
system:serviceaccount:openshift-user-workload-monitoring:prometheus-operator
system:serviceaccount:rook-ceph:rook-ceph-system
system:serviceaccount:velero:velero-server
Groups: okdprod-cluster-admin
system:cluster-admins
system:masters
Error during evaluation, results may not be complete: clusterrole.rbac.authorization.k8s.io "system:openshift:scc:hostmount-anyuid" not found
If I run oc access-matrix r secret -n=istio-system
It shows that a lot of other groups can delete the secret
NAME KIND SA-NAMESPACE CREATE GET LIST WATCH UPDATE PATCH DELETE DELETECOLLECTION
okdprod-cluster-admin Group ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
okdprod-cluster-reader Group ✖ ✔ ✔ ✔ ✖ ✖ ✖ ✖
okdprod-cluster-user Group ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
okdprod-self-provisioner Group ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
I've also verified that "who-can" is correct. The group "okdprod-self-provisioner" can create a secret, but not delete a secret.
But the access-matrix shows that the group can do everything.
Expected behavior
the example-go-info service account is defined at https://github.com/rgl/rancher-single-node-ubuntu-vagrant/blob/da6c6030b5d4def7542b22b8fa8d368c4cad38be/examples/go-info/deployment.yml as:
apiVersion: v1
kind: ServiceAccount
metadata:
name: example-go-info
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-read
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: example-go-info-pod-read
subjects:
- kind: ServiceAccount
name: example-go-info
roleRef:
kind: Role
name: pod-read
apiGroup: rbac.authorization.k8s.io
Actual behavior
The command returns nothing:
$ kubectl access-matrix --sa example-go-info --namespace default
NAME LIST CREATE UPDATE DELETE
Steps To Reproduce
Steps to reproduce the behavior:
Context:
# kubectl access-matrix version --full
rakkess: v0.4.1
platform: linux/amd64
git commit: 946f6e2126cb584957eb0ad8cc0342fda7b8a1c9
build date: 2019-07-01T23:25:45Z
go version: go1.12.5
compiler: gc
The current implementation of rakkess
with client-go library and genericclioptions works well, but it results in a rather large binary. However, the api machinery is only used to query SelfSubjectAccessReview
for all resources and a list of server resources.
A different approach would be to call out to kubectl
via exec.Command
and create the SelfSubjectAccessReview
through a yaml string. All additional args would then be forwarded to kubectl
. Thus, all the heavy lifting is done by kubectl
, whereas rakkess
could remain small ans slim.
The following items need to be evaluated:
kubectl
clientkubectl
binary is usually called kubectl.exe
?Expected behavior
I want results for use
verb.
Actual behavior
Right now if I list the resource podsecuritypolicy
and define verb use
I get error.
Steps To Reproduce
Steps to reproduce the behavior:
Just setup a cluster that has PodSecurityPolicy admission plugin enabled. Also install PSP in your cluster, since they are not automatically installed. If you want an example of a PSP then just do kubectl apply -f URL
on the files in these two links: https://github.com/kinvolk/terraform-render-bootkube/blob/kinvolk-master/resources/manifests/psp-restricted.yaml and https://github.com/kinvolk/terraform-render-bootkube/blob/kinvolk-master/resources/manifests/psp-privileged.yaml
Once you have cluster with PSP run following command:
$ rakkess resource psp --verbs use
ERRO[0000] unexpected verbs: [use]
-v debug
to show extra logging.$ rakkess resource psp -v debug --verbs use
DEBU[0000] Set log-level to debug
ERRO[0000] unexpected verbs: [use]
Context:
$ rakkess version --full
rakkess: v0.4.0
platform: linux/amd64
git commit: b851b199ec7f14bad3b4f7ddec27aa72a6258f31
build date: 2019-04-26T18:43:27Z
go version: go1.12.4
compiler: gc
Additional context
The PSPs are made usable by using verb use
in the Role or ClusterRole and then it is bound to serviceaccounts or users using RoleBinding ro ClusterRoleBinding. Like here is an example from the PSP snippets link I have posted above.
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: restricted-psp
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames:
- restricted
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: restricted-psp-system-authenticated
roleRef:
kind: ClusterRole
name: restricted-psp
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
Above snippet is from this source https://github.com/kinvolk/terraform-render-bootkube/blob/0913331140747fd464946981c1d43a895d7a630b/resources/manifests/psp-restricted.yaml#L52-L75
Firstly, this is an amazing tool!
Unfortunately, we use oidc via dex for authentication. Is there any way we could make the --as
function work with that?
Before the normal output, there is extra output with no resource name, and empty permissions.
It looks like if the normal output has N lines, then there will be N empty lines.*
Expected behavior
$ kubectl access-matrix --namespace=default
NAME LIST CREATE UPDATE DELETE
bindings ✔
configmaps ✔ ✔ ✔ ✔
controllerrevisions.apps ✔ ✔ ✔ ✔
cronjobs.batch ✔ ✔ ✔ ✔
...
Actual behavior
$ kubectl access-matrix --namespace=default
NAME LIST CREATE UPDATE DELETE
✖ ✖ ✖ ✖
✖ ✖ ✖ ✖
✖ ✖ ✖ ✖
✖ ✖ ✖ ✖
...
bindings ✔
configmaps ✔ ✔ ✔ ✔
controllerrevisions.apps ✔ ✔ ✔ ✔
cronjobs.batch ✔ ✔ ✔ ✔
...
Steps To Reproduce
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.3", GitCommit:"c92036820499fedefec0f847e2054d824aea6cd1", GitTreeState:"archive", BuildDate:"2021-10-28T06:55:39Z", GoVersion:"go1.17.2", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.1", GitCommit:"5e58841cce77d4bc13713ad2b91fa0d961e69192", GitTreeState:"clean", BuildDate:"2021-05-21T23:01:33Z", GoVersion:"go1.16.4", Compiler:"gc", Platform:"linux/amd64"}
$ kubectl access-matrix version --full
rakkess: v0.5.0
platform: linux/amd64
git commit: e52bef14064d68573850f4f64f825b7be4800457
build date: 2021-07-25T09:13:28Z
go version: go1.16.6
compiler: gc
Output above was reproduced on a "fresh" KinD cluster (just created with kind create cluster
).
The full debug output is too long to be attached to this issue so I'm attaching it to this public gist:
https://gist.github.com/jpetazzo/0d39b6a92e927e4ff3fa5dfc549e91af
... I was wondering if that could be linked to my version of kubectl
; but if I understand correctly rakkess doesn't rely on kubectl
in any way, right?
Thanks!
See #21
Krew instructions have no link to krew itself.
rakkess resource
currently evaluates the role.rules.resources
field to determine the resources that this role applies to. However, there is also the role.rules.resourceNames
field which identifies specific resources by their name.
See kubectl explain role.rules
:
resourceNames <[]string>
ResourceNames is an optional white list of names that the rule applies to.
An empty set means that everything is allowed.
Rakkess should support subject access review such as
# rakkess <subcmd> <resource> <resource-name> ...opts
rakkess r cm ingress-controller-leader-nginx -n ingress-nginx
In a cluster with a CRD named Organization
(long name: organizations.security.giantswarm.io
), the following command works fine:
$ kubectl access-matrix resource organizations
However, when I use the full CRD name instead, this happens:
$ kubectl access-matrix resource organizations.security.giantswarm.io
ERRO[0005] determine requested resource: no matches for /, Resource=organizations.security.giantswarm.io
I expected to be able to use the full name, like it's the case with kubectl get <resource>
.
Hello,
Firstly thanks for great app! Definitely useful at work!
Is it possible to present a comparison of permissions between different users or service accounts? In the attached image I present the visual aspect of such a comparison. I normally take a few screenshots and then glue them together in GIMP to get this effect.
Example calls that this feature would do:
rakkess --namespace ...-test --as appadmin --as view --verbs ...
rakkess --namespace ...-test --context ctx-appadmin-test-cluster --context ctx-view-test-cluster --verbs ...
rakkess --namespace ...-test --as appadmin --sa sa-view --verbs ...
Regards
Piotr Minkina
Currently, the access matrix for a service account has to be generated by
rakkess --as system:serviceaccount:ingress-nginx:nginx-ingress-serviceaccount -n ingress-nginx
The user string system:serviceaccout:<namespace>:<service-account>
is quite complicated and makes it hard to use.
Make it possible to specify the service-account in a simplified way, e.g.
rakkess --as-service-account nginx-ingress-serviceaccount -n ingress-nginx
It should be an error to specify --as-service-account
without the --namespace
option, because SAs are namespaced.
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.