cloudtools / ssh-cert-authority Goto Github PK
View Code? Open in Web Editor NEWAn implementation of an SSH certificate authority.
License: BSD 2-Clause "Simplified" License
An implementation of an SSH certificate authority.
License: BSD 2-Clause "Simplified" License
If you attempt to request a cert using an ed25519 key ssh-cert-authority aborts in an ambiguous way:
$ ssh-cert-authority request -e test
Please give a reason: testing ed25519
Trouble parsing your public key ssh: no key found
We should provide a more helpful error message. Also update the documentation to describe supported key types.
Know that key type support is driven by the keys supported by Go's SSH implementation.
I enabled auto signing for an environment as follows:
{
"myEnv": {
"AuthorizedSigners": {
"<redacted>": "omar.darwish"
},
"AuthorizedUsers": {
"<redacted>": "omar.darwish"
},
"NumberSignersRequired": -1,
"MaxCertLifetime": 86400,
"PrivateKeyFile": "/path/to/key.rsa"
}
}
I request certificates for this environment like so:
$ ssh-cert-authority request --principals myUser --environment myEnv --reason "debugging myEnv" --valid-before "1h59m0s"
Which returns Cert request rejected: FPRMTRTVURB54QAV
.
This is incorrect because if I attempt to sign the same ID, it reports that Certificate already signed. Thanks for trying.
I can also get this certificate using the same Id. It is a valid certificate which has the same expiration I set above, so it clearly is accepting my request, signing it, and is able to generate a certificate.
On your home page (README.md), you have the following quote:
ECDSA support is nonexistent on OS X hosts unless your users build openssh from scratch (or homebrew). This is considered painful. This may not be a problem on more modern versions of OS X (i.e. high sierra) but I haven't tried it.
I can confirm that macOS Mojave comes with OpenSSH_7.9p1, LibreSSL 2.7.3
, which supports all four key types (RSA, DSA, ECDSA, and Ed25519). You may want to update your documentation.
It looks like an AuthorizedRequester
can sign their own cert if they are also an AuthorizedSigner
for the same environment. It seems intuitive for me that some requesters would also be signers for the same environment, and that requesters should not be able to sign a request for their own pubkey by default.
I want to ssh to different environments with a single pair of ssh-key.
I executed request
and get
multi times and ssh to different environments, it worked ok.
But when I restarted my computer, I can't ssh to those machines except the last environment I requested.
I found it's because ssh-agent restarted, all certs in ssh-agent were lost. The last one I requested downloaded id_rsa-cert
, so it still worked.
So is there a way to make different environment singers to sign the same cert?
Hi, currently when I try to execute build.sh, I get the following error:
~/go/src/ssh-cert-authority$ bash build.sh
../golang.org/x/crypto/ssh/keys.go:492: undefined: crypto.Signer
Is there some way to build and run this software without using docker? I'm unfamiliar with both docker and go, so quite newbie here...
Today the service spins up on 0.0.0.0:8080 and it should probably default to 127.0.0.1:8080 and encourage people to run it behind a real web server that knows how to terminate TLS among other things.
Right now, it appears that a signer requires access to the server hosting ssh-cert-authority
in order to view the logs to get access to the signing IDs (that, or the requestor has to provide it by other means). Is there a way to get a list of pending signing requests automatically?
Sorry if this is a stupid question. I see the LICENSE file, but I'd like to know if this is a standard license like MIT, BSD, etc. If I had to guess I would say this is a (Free)BSD-style license?
Hi,
I use the application running as a daemon always available, but sometimes when requesting a certificate it crashes and leave the trace I attach to this issue. Let me now if you need more information.
Thanks.
Unencrypted (no passphrase) Ed25519 SSH keys work fine, but when using an encrypted (with a passphrase) Ed25519 SSH key, the following currently happens...
...
SSH Key Passphrase [none]: •••••
error adding private key: error parsing private key: ssh: cannot decode encrypted private keys
...
$ >
When you do request_cert --environment dev
this generates a unique ID which I assume is specific to that environment/request. I would assume that I should be able to do sign_cert <ID>
and be able to drop the --environment dev
from the command but this is not the case. What's interesting is that I can do sign_cert --environment other <ID>
and it works. I think the requirement of --environment
should be dropped altogether for the sign_cert
and request_cert
operations.
Thoughts?
We internally use Alpine for our docker containers.
Regardless of this, I am unable to build using the provided ubuntu buildenv or my standard alpine environment.
All builds regardless of build platform result in the same error:
./sign_certd.go:366: certChecker.IsAuthority undefined (type ssh.CertChecker has no field or method IsAuthority)
Using go versions: 1.7.3 on ubuntu, 1.7.5/1.8.1 on OSX and 1.7.3 on Alpine
Any assistance would be appreciated.
I will get one of my internal Go developers to take a look.
When requesting a certificate for a plain file key, fingerprint parsing got broken by 7952e33.
2019/02/01 10:03:41 Server running version 1.7.0-0-g7952e33
2019/02/01 10:03:41 Using SSH agent at /tmp/ssh-NB2G9PMmzz5F/agent.1
2019/02/01 10:03:41 Added private key for env test: ad:0a:8a:8b:be:a0:ec:be:dd:ba:b5:a2:f4:a1:7f:1d
2019/02/01 10:03:41 Server started with config map[string]ssh_ca_util.SignerdConfig{"test":ssh_ca_util.SignerdConfig{SigningKeyFingerprint:"ad:0a:8a:8b:be:a0:ec:be:dd:ba:b5:a2:f4:a1:7f:1d", AuthorizedSigners:map[string]string(nil), AuthorizedUsers:map[string]string{"01:f5:24:35:51:52:13:b9:8e:a9:3b:0f:00:20:fa:10":"calle@test"}, NumberSignersRequired:-1, SlackUrl:"", SlackChannel:"", MaxCertLifetime:600, PrivateKeyFile:"/etc/ssh/ca/test_ca_ed25519", KmsRegion:"", CriticalOptions:map[string]string(nil)}}
$ ssh-cert-authority --version
ssh-cert-authority version 1.7.0-0-g7952e33
$ ssh-cert-authority request --environment test --reason test
Ignoring invalid private key url: '01:f5:24:35:51:52:13:b9:8e:a9:3b:0f:00:20:fa:10'. Error parsing: parse 01:f5:24:35:51:52:13:b9:8e:a9:3b:0f:00:20:fa:10: first path segment in URL cannot contain colon
It seems that the breakage is in the client side of things, because when I request a certificate from an up-to-date server, using an older client build it still works.
Does ssh-cert-authority
work outside of AWS? On my laptop outside of AWS, built off 5c22404, something attempts to read EC2 Instance metadata, and fails:
environment_name=dev ssh-cert-authority encrypt-key \
--generate-rsa \
--key-id arn:aws:kms:us-west-2:1234567891011:key/ssh-certificate-authority \
--output .ssh-ca/ca-key-dev.kms
Unable to determine our region: RequestError: send request failed
caused by: Get http://169.254.169.254/latest/meta-data/placement/availability-zone: dial tcp 169.254.169.254:80: connect: host is down
I tried with and without ~/.ssh_ca/sign_certd_config.json
or AWS_DEFAULT_REGION
and AWS_REGION
environment variables and received the same error.
I am happy to send a PR, but the only Dial
invocations I see are:
$ git grep Dial
request_cert.go: conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
request_cert.go: return cli.NewExitError(fmt.Sprintf("Dial failed: %s", err), 1)
sign_cert.go: conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
sign_cert.go: return cli.NewExitError(fmt.Sprintf("Dial failed: %s", err), 1)
sign_certd.go: sshAgentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
sign_certd.go: return cli.NewExitError(fmt.Sprintf("Dial failed: %s", err), 1)
Unrelated, but region
is readily available from http://169.254.169.254/latest/dynamic/instance-identity/document rather than having to query http://169.254.169.254/latest/meta-data/placement/availability-zone and then trim the Availability Zone's last character to get the Region.
I'd like to add a feature to make sure a requester can't request a cert for a Principal that has a different user's name (e.g. if Alice is an AuthorizedRequester, she can't request a cert for Bob@*
).
It doesn't look like this is possible currently. And it also looks like the person who requested the cert in the first place is not stored anywhere persistently.
If that's correct, it seems like I would have to do some surgery. I.e., add a field to the certRequest
struct to persistently store who requested that cert in the first place.
Is this accurate? Any thoughts here?
Hey,
thank you for your project.
I think your project could hit a sweet spot for me/us between manually signing keys and setting up a complete vault. But I'm still hitting a wall.
Could you perhaps tell me what Im doing wrong?
root@identity-1:~/ssh-cert-authority# ssh-keygen -f my_ssh_cert_authority
Generating public/private rsa key pair.
Your identification has been saved in my_ssh_cert_authority.
Your public key has been saved in my_ssh_cert_authority.pub.
The key fingerprint is:
SHA256:Q9yWgSdLa2VLgjF/xeiwytoP6xmz7C87WsLY5G6ekKQ root@identity-1
The public key would than be distributed to all servers.
Next, every user would generate their private CA (?)
root@identity-1:~/ssh-cert-authority# ssh-keygen -f my_ssh_cert_authority_private
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in my_ssh_cert_authority_private.
Your public key has been saved in my_ssh_cert_authority_private.pub.
The key fingerprint is:
SHA256:xhHdtjZgGAYznjlSvc/qN8H2p2P6AhAGkkNYJq2WOzg root@identity-1
root@identity-1:~/ssh-cert-authority# ssh-keygen
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Hg/ZTAn+BkoICveRpi0hkupEwYHmN7TTOXWv0fCwSKA root@identity-1
So, I would put the key fingerprint of the private CA as an authorizedUser as well as identity
Therefore my sign_certd_config.json
would look like
{
"production":{
"NumberSignersRequired":1,
"MaxCertLifetime":86400,
"PrivateKeyFile":"/root/ssh-cert-authority/my_ssh_cert_authority",
"AuthorizedUsers":{
"SHA256:xhHdtjZgGAYznjlSvc/qN8H2p2P6AhAGkkNYJq2WOzg":"root@identity-1"
}
}
}
With that at hand, I started the server
root@identity-1:~/ssh-cert-authority# ssh-add my_ssh_cert_authority
Identity added: my_ssh_cert_authority (my_ssh_cert_authority)
root@identity-1:~/ssh-cert-authority# ./ssh-cert-authority runserver --config-file ./sign_certd_config.json --listen-address 0.0.0.0:8080
2021/04/13 07:21:11 Server running version 2.0.0-6-g59dae40
2021/04/13 07:21:11 Using SSH agent at /tmp/ssh-UGpiNK15qM/agent.26492
2021/04/13 07:21:11 Added private key for env production: d6:05:03:9a:40:f9:db:11:80:eb:cd:43:39:9f:7a:a9
2021/04/13 07:21:11 Server started with config map[string]ssh_ca_util.SignerdConfig{"production":ssh_ca_util.SignerdConfig{SigningKeyFingerprint:"d6:05:03:9a:40:f9:db:11:80:eb:cd:43:39:9f:7a:a9", AuthorizedSigners:map[string]string(nil), AuthorizedUsers:map[string]string{"SHA256:C4wJWc3767N6rQlXqtVzxpWmtThOrQMFCHI4vU7Wxp4":"root@identity-1"}, NumberSignersRequired:1, SlackUrl:"", SlackChannel:"", MaxCertLifetime:86400, PrivateKeyFile:"/root/ssh-cert-authority/my_ssh_cert_authority", KmsRegion:"", CriticalOptions:map[string]string(nil)}}
Lets first get a requester_config.json
mkdir -p ~/.ssh_ca/
./ssh-cert-authority generate-config --url=http://localhost:8080 > ~/.ssh_ca/requester_config.json
and the content looks like
{
"production": {
"PublicKeyPath": "/root/.ssh/id_rsa.pub",
"SignerUrl": "http://localhost:8080/"
}
}
root@identity-1:~/ssh-cert-authority# ssh-keygen -V +1h -s my_ssh_cert_authority_private -I confusedGithubPerson -n ubuntu ~/.ssh/id_rsa.pub
Signed user key /root/.ssh/id_rsa-cert.pub: id "confusedGithubPerson" serial 0 for ubuntu valid from 2021-04-13T07:33:00 to 2021-04-13T08:34:58
Lets check the public key
root@identity-1:~/ssh-cert-authority# ssh-keygen -L -f ~/.ssh/id_rsa-cert.pub
/root/.ssh/id_rsa-cert.pub:
Type: [email protected] user certificate
Public key: RSA-CERT SHA256:Hg/ZTAn+BkoICveRpi0hkupEwYHmN7TTOXWv0fCwSKA
Signing CA: RSA SHA256:xhHdtjZgGAYznjlSvc/qN8H2p2P6AhAGkkNYJq2WOzg
Key ID: "confusedGithubPerson"
Serial: 0
Valid: from 2021-04-13T07:33:00 to 2021-04-13T08:34:58
Principals:
ubuntu
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rc
./ssh-cert-authority request --environment production --reason "Do important maintenance work"
but will receive
Cert request rejected: Cert not valid: not signed by an authorized key
on the client-side
and the server will show
2021/04/13 07:36:51 Invalid certificate signing request received from 127.0.0.1:40682, ignoring
This means I do something wrong and are stopped here
ssh-cert-authority/sign_certd.go
Lines 405 to 409 in 6c6c463
My mistake must be in the sign_certd_config.json
, but I don't understand how it can be wrong as the AuthorizedUsers
is exactly the key that is used for my request.
Could you point in the correct direction?
OpenSSH 8.2 has deprecated rsa-sha signatures in certificates. If you try to use an SSH Certificate to login to a system upgraded to 8.2 that was previously working, you will get the error ssh-rsa signature algorithm not supported
reported by SSHD. This can also happen with Host Certificates if the client SSH version is upgraded to 8.2.
Further reading on this here: https://ibug.io/blog/2020/04/ssh-8.2-rsa-ca/
In order to resolve this, a newer SHA256 or SHA512 hash is required. I found a way to request these newer hashes in the x/crypto/ssh/agent code, but it is hidden behind the unexported agentKeyringSigner struct without an exported Interface for the needed SignWithOpts.
There is a way to work around this by declaring a local Interface for SignWithOpts and casting the returned Signer to that Interface. I've implemented this approach here:
digitallumens/ssh-cert-authority@70baa54
I don't think there would be an easier or cleaner way to doing this without some changes made to x/crypto/ssh. If this looks reasonable, I can make a pull request.
It would be useful to store signed certificates in a sql database. This could be used for generating revocations, as well as auditing.
Would there be any interest in this?
I'm unable to sign requests as ssh-cert-authority doesn't seem to be able to find the keys that are stored in ssh-agent.
Generating CA key:
root@server:/$ ssh-keygen -C 'certificate_authority' -f my_ssh_cert_authority
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in my_ssh_cert_authority
Your public key has been saved in my_ssh_cert_authority.pub
The key fingerprint is:
SHA256:JlpLr7dc6jnF0CijxBpd6XPaSK9BCegZnvxgh8jJlVY certificate_authority
The key's randomart image is:
+---[RSA 3072]----+
| .oE . |
| o+. o |
|o=+B + . o |
|.+@ = O + . |
| . B ++XSo |
| . o++=o o |
| . .o... |
| .oo+ |
| .o*o |
+----[SHA256]-----+
Getting MD5 of CA key:
root@server:/$ ssh-keygen -l -E md5 -f my_ssh_cert_authority
3072 MD5:ed:86:c2:b0:7d:af:64:c7:ae:62:bf:f3:2c:e8:88:18 certificate_authority (RSA)
/root/.ssh_ca/sign_certd_config.json:
{
"production":{
"NumberSignersRequired":-1,
"MaxCertLifetime":86400,
"SigningKeyFingerprint":"ed:86:c2:b0:7d:af:64:c7:ae:62:bf:f3:2c:e8:88:18",
"AuthorizedUsers":{
"e8:b4:55:04:79:37:ef:df:d4:30:53:ef:41:2b:46:ef":"user@client"
}
}
}
Importing key and starting ssh-cert-authority server:
root@server:/$ eval `ssh-agent -s`; ssh-add my_ssh_cert_authority; ssh-add -E md5 -l; ssh-agent ssh-cert-authority runserver
Agent pid 8
Identity added: my_ssh_cert_authority (certificate_authority)
3072 MD5:ed:86:c2:b0:7d:af:64:c7:ae:62:bf:f3:2c:e8:88:18 certificate_authority (RSA)
Server running version 1.7.1
Using SSH agent at /tmp/ssh-XXXXXXFmAAPo/agent.1
Server started with config map[string]ssh_ca_util.SignerdConfig{"production":ssh_ca_util.SignerdConfig{SigningKeyFingerprint:"ed:86:c2:b0:7d:af:64:c7:ae:62:bf:f3:2c:e8:88:18", AuthorizedSigners:map[string]string(nil), AuthorizedUsers:map[string]string{"e8:b4:55:04:79:37:ef:df:d4:30:53:ef:41:2b:46:ef":"user@client"}, NumberSignersRequired:-1, SlackUrl:"", SlackChannel:"", MaxCertLifetime:86400, PrivateKeyFile:"", KmsRegion:"", CriticalOptions:map[string]string(nil)}}
/home/user/.ssh_ca/requster_config.json:
{
"production": {
"PublicKeyPath": "/home/user/.ssh/id_rsa.pub",
"SignerUrl": "http://server.local:8080/"
}
}
Making a request:
user@client:~$ ./ssh-cert-authority r -r testing -p user -e production
Cert request id: MKEWDZH3LZ2W4
Request response:
Received 0 signatures for MKEWDZH3LZ2W4, signing now.
Couldn't find signing key for request MKEWDZH3LZ2W4, unable to sign request: Unable to find your SSH key (ed:86:c2:b0:7d:af:64:c7:ae:62:bf:f3:2c:e8:88:18) in agent. Consider ssh-add
Cert request serial 7100313923624007022 id MKEWDZH3LZ2W4 env production from e8:b4:55:04:79:37:ef:df:d4:30:53:ef:41:2b:46:ef (user@client) @ 172.21.0.1:44670 principals [user] valid from 1642207193 to 1642214513 for 'testing'
While it's awesome to build the project using the included Dockerfile, it would be cool to be able to build a container that has the built linux binary and can be run as an isolated server instance. This would however mean having two dockerfiles, which is a little strange I suppose.
Thoughts?
I'm wondering if thought has been put into having ssh-cert-authority
not only handle signing user keys, but also host keys? A similar challenge exists when one wants to sign host keys to allow for consistent known_hosts
files. The CA's private key is needed to sign the public keys, and having the private key copied to the hosts is not desirable. The result is needing to copy public keys back and forth, which is part of what this project solves.
i am trying to use this software but i am getting stuck at retrieving the signed key.
[root@ip-172-19-3-177 ~]# ./ssh-cert-authority get --environment production 42TUJNQ5Q6BQV4CT
Couldn't find ssh key for cert.
Previously I've signed successfully and here's the server message.
2016/05/21 19:03:04 Cert request serial 2 id 42TUJNQ5Q6BQV4CT env production from 10:ab:fd:4c:ad:e8:d9:17:e3:f6:38:82:3a:3f:27:ac (sava) @ 127.0.0.1:58826 principals [sdt_user] valid from 1463857264 to 1463864584 for 'Do important maintenance work' 2016/05/21 19:03:27 Received 1 signatures for 42TUJNQ5Q6BQV4CT, signing now.
I have my keys active with the agent:
[root@ip-172-19-3-177 ~]# ssh-add -l
2048 10:ab:fd:4c:ad:e8:d9:17:e3:f6:38:82:3a:3f:27:ac ./test (RSA)
4096 10:d7:ac:d1:86:d7:e1:4c:e9:27:76:d1:bb:1f:e2:92 ./ca-key-production (RSA)
what am i doing wrong ?
I read through the provided documentation and the more I read the more I became unsure that the original problem is solved by this project.
The line that says that signers should have CA private key on their keychain and that the service provided by this project does not have access to private keys means that one with the CA private key (one of the signers) can simply sign anything without any need to use the service.
This brings a question of the goal of this project and what the project tries to solve. Is it just some convenient way to distribute public keys for signing? If so, this approach with multiple people having access to the CA private key stands against good security practices since it would be impossible to detect who actually signed the key used for malicious activity on the server (all in all, all signers are using the same CA private key).
A much better approach would have been if the signing entity was behind the ss-cert-authority and would not be accessible to anyone directly, but through your service only. Then if the proper authorisation was implemented (e.g. through the list of fingerprints who allowed to approve the signing of the request) the signing entity (e.g. implemented via HSM or something like that) would sign the request.
I get this warning on most commands.
DEPRECATED Action signature. Must be `cli.ActionFunc`. This is an error in the application. Please contact the distributor of this application if this is not you. See https://github.com/urfave/cli/blob/master/CHANGELOG.md#deprecated-cli-app-action-signature
Everything still seems to work for now.
I was trying to build the current master branch as per https://github.com/cloudtools/ssh-cert-authority/blob/master/BUILDING.rst.
After executing ...
docker run \
-v `pwd`:/build/ssh-cert-authority/go/src/github.com/cloudtools/ssh-cert-authority \
-t cloudtools/ssh-cert-authority-buildenv \
bash build.sh
... the build process fails with the following error message after a few minutes:
package github.com/cpuguy83/go-md2man/v2/md2man: cannot find package "github.com/cpuguy83/go-md2man/v2/md2man" in any of:
/build/go-build/go/src/github.com/cpuguy83/go-md2man/v2/md2man (from $GOROOT)
/build/ssh-cert-authority/go/src/github.com/cpuguy83/go-md2man/v2/md2man (from $GOPATH)
../../codegangsta/cli/docs.go:11:2: cannot find package "github.com/cpuguy83/go-md2man/v2/md2man" in any of:
/build/go-build/go/src/github.com/cpuguy83/go-md2man/v2/md2man (from $GOROOT)
/build/ssh-cert-authority/go/src/github.com/cpuguy83/go-md2man/v2/md2man (from $GOPATH)
Makefile:54: recipe for target 'test' failed
make: *** [test] Error 1
It seems like v2 of go-md2man was finally released and is not available as a separate branch anymore.
Hi there,
I stumbled on this project because I was searching for a solution whereby people or systems requiring access to other systems need authorization to do so. While reading the README
of this project, this particular paragraph seemed to fit my requirements exactly:
You're now an SSH cert signer. The problem, however, is that you probably don't want to be the signer. Signing certificates is not fun. And it's really not fun at 3:00AM when someone on the team needs to access a host for a production outage and you were not that person. That person now has to wake you up to get a certificate signed. And you probably don't want that. And now you perhaps are ready to appreciate this project a bit more.
However, after reading the rest of the documentation, I'm not exactly sure how this project solves this problem. If someone on the team needs production access at 3am, would they not still need to wake you up to "sign" the request via this tool?
Would it be possible to support SHA256 fingerprints in the config? The latest Ubuntu LTS release defaults to SHA256 fingerprints.
I realize that I can list the MD5 fingerprint, but its annoying and I'd like to banish md5 from everything if possible.
Using ssh-cert-authority version 2.0.0-6-g59dae40 built with go version go1.17 linux/amd64 when I run ssh-cert-authority request -e production -r "Testing" -p vendion -c /home/vendion/.config/ssh_ca/requester_config.json
it errors out with the following error:
Dial failed: dial unix: missing address
My requester_config.json file is as follows
{
"production": {
"PublicKeyPath": "/home/vendion/.ssh/id_ed25519_uf.pub",
"SignerUrl": "https://ssh-ca.utiliflex.com/"
}
}
This file was created by ssh-cert-authority generate-config --url 'https://ssh-ca.utiliflex.com'
so I don't know what address could be missing that it is complaining about.
The security of this project is paramount and having an untrusted build service acting as a blackbox building the project is potentially dangerous. This issue is to track performing a soft audit of drone.io via whatever documentation they will provide or finding a different service altogether.
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.