then within one hour the token needs to be refreshed with a refresh token if you don't work with refresh token you have to go through the whole login flow again this is unix time not before should be time now and issued at is also time now so then we have this token but we still need to sign the token and i want to make one more change to this token so we have the claims but we also need something specifically set in the header for our jwks to work so the way this public key endpoint is going to work this jwks.json is that we need to specify a key id and because we only have one key we are just going to specify a static number 0001 is our key because we only have one private key and this is the key id so the key id stands for key id and this is something that we need to put in the header now we can sign this jlt with our private key token signed string so we're going to retrieve the signed string from this token and we need to get the private key for that this returns the signed token signed id token an error if there's something going wrong if something went wrong then we need to capture this signed string error error here how are we going to return this we have this oidc token for that so in types we have this token so this is access token token type reverse token expires in an id token that we typically should return at the token endpoint so we're going to use this one oidc token so this is also standardized token output is oidc token and token has the access token the token type the refresh token expires in an id token so we will actually need to create two tokens because we just created the id token which can be used to validate whether we are authenticated but we also need an access token let's start with id token is signed id token and then we're going to just copy paste this and then this will be our access token signed access token and then access token is the signed access token but the access token needs to be looking a little bit different because it has different audience and the audience is actually a string slice of the endpoint it can access so what can it access it can access any API that we would give access to as in once we have a second application server and we would enter that in the audience here then then the second application server could actually parse the jlt have a look in the audience have a look whether it has access to a specific endpoint right now we are just going to give it access to our user info endpoint so we have our URL and with this token the application server can go to our user info endpoint and we will then return some user info so this is the difference between access token and our id token token type it's going to be bearer it's going to be a bearer token so then we can use authorization bearer and then the token the jlt token in htp access calls what else do we have refresh token so if you want to supply a refresh token for example when the scope is offline access then you just need to generate a random string for here and to make another endpoint that if this refresh token is supplied that you issue a new jlt currently not going to do that we are going to focus on this first flow that we are trying to implement we have like sparse in as well expires in is an integer how many minutes will it expire in so we have one hour token output then we still need to parse it token output json marshal our token output out an error and then we can check for errors token marshal error just in case that we have an error and we need to do one more thing so we are going to just write this first to the app server where it's connecting which we also need to make sure that we remove this code so we have this code s codes where we keep all the codes now that we issued a token we need to get rid of this so s codes and we have the code the code is our post form get code so you also need to remove this code from the map so then when the app server would execute it again then it will fail because we don't have this code anymore you just have to go through the whole flow again if you want to have a new token you cannot reuse your codes that looks okay i think could be that there's still a mistake how do we check for that well that's why i wrote these tests token tests what is this is going to do first going to hit authorization endpoint and here i will also remove this secret because it's not necessary for our first endpoint i just going to paste it all this code multiple times so that's why this the same mistake is in all these tests so first hit authorization flow we get the code or the redirect we get the redirect we go to the login flow we get the code and we need to then exchange a code into a token and then we need the secret actually so this all and i didn't specify this last time this also uses this test config test config is defined right here in hp test and whenever we run our test we are going to do a setup of this test config which generates an rsa key so we don't need an rsa key just to run the test the test will actually generate its own key and we'll have here a map of some default configuration well let's hope it works no it didn't work and standard claims he should add needs to be of in 64 he should add added time now needs to be unix and that's an in 64 and this also needs to be unix so that's why we have these tests easy to then find whether your code is working or not still not working get on marshal string into ghost truck because we have two times we have it two times once for id token once for access token and this works got valid token from a token endpoint so i'm gonna leave it at that and then in the next lecture we can try to see whether our application server can now get this token with the core that was supplied at the callback endpoint in our application server now that we have written the slash token endpoint let's try to add this code to our web application to hit this token endpoint with our code and then retrieve our token that will be step one to retrieve a token step two will be to validate the token so i will first try to get a token and then we need to validate the token to validate the token we need the public key so we need another endpoint at the authorization server for that the jwks endpoint which will output the public keys we will need to parse that and then the public key we can use to validate our jwt that was returned or our jwts that were returned so let's first start with a post request on this slash token endpoint we have still the app server and then here in the callback we have the code this code we need to validate we have a jwt and jwt test so if you use this jwt signature get token from code then it will be easier for us to validate our code because we have a test in jld underscore test here we have a test to test to get token from code so let's try to use this code get token from code what do we need for that the token URL the jwks URL the redirect ui client ID client secret so we can use this we'll just copy paste it for now this discovery endpoint token URL is discovery token endpoint jwks is discovery jwks ui redirect ui is static client ID is client ID as an environment variable then we have the client secret which will also pass us an environment variable and then we have the code which is coming as a query parameter what does this return a token claims an error and we can say token received claims subject i'm not 100% sure whether i will use these standard claims because they are discouraged maybe just for the simple get token from from code but really map claims is much more flexible so we probably should be using that token received if token or we also have the claims here if you want token claims maybe you shouldn't even return the claims on token dot let's keep it like this for now save this and let's start working on this get token from code we'll have to do an HTTP post request on the token URL and with the post we have a URL content type and a body what is the content type going to be it's a specific content type for form encoding and because this is actually a special type there is post form post form issue as opposed to specified URL and then the content type header is set to application x www for your line code so that we don't have to set it manually token URL and then the data the URL values so URL values is of type URL values it's a map string and then a slice of strings we have some add functions that we can use what do we all need you need to pass the client ID client ID client secret redirect to your eye the code and this grant type authorization code then we have this post form responds an error if we have an error then turn nil nil error defer res body close and then we can read the body res body body error is IO read all because this is an IO reader if res status code is not 200 let's also return something we will then say status code was not 200 and I'll just output the body for now to the screen here to see something happened not sure what's going to be this maybe we should just return not yet fully implemented and then here in the main we can just say get token from code error as long as we didn't write the complete flow then we will get this error which makes sense I think so this get token from error there's one thing we didn't do and that is we didn't validate our state so we generated here our state we generated here our state in the index get random string but we didn't store it anywhere so let's try to store it somewhere we are not going to store anything in this state or match any user with this state so I think it's enough to just store the state and then see if we issued this random state string in the callback if not then we just reject the request if you are going to store something in the state or match a user or something else with it then I would recommend you to encrypt the state so that nobody can change or read it what's really inside and you can even pass it in a cookie with the client so that at the callback you could compare it with the client so I'm going to keep it simple and create a state map string boolean make map string boolean here for the state and when I create this state I'm going to add this the state called states states so that way I for sure know that the request originated from this index page and then here in the callback we are going to check if okay a states and then the state our URL cray get state if it's not okay then we will just return an error then we will just return error state mismatch error and then we can remove this state delete a states the state so that also means that if you're going to refresh this callback page it will not work anymore so we'll have to go back through the flow to get a new state should we try this out I cannot test my code yet because I'm just checking whether I'm getting a token we would still need to validate the token let's go and run the server client secret is the secret which is conferred in the config.tml or dc endpoint go run and then we also need to specify the jail at t.co let's open the browser localhost 8081 login we can supply our login and password information get token from code not yet fully implemented but did we get the token output on our screen yes we did so here we have the body the access token and the id token will also be swear there refresh token expires in id token now we just need to validate this token so this is jlt you can actually input it in jlt.io which is a simple json web token tool and what do we see algorithm rs256 the key id the type and here we have the audience expiration date issued at issuer not valid before and the subject if you would paste our public key here then it would also be able to validate our signature so it can decode it but it cannot validate it because we still need to validate it to validate it we need to get the public key and to get the public key we need to make this endpoint the jwks endpoint and that's what we'll be doing next now that our web application received our tokens we still need to parse and validate those tokens and to validate those tokens we are going to do a get request to the jwks endpoint and that endpoint will supply us the public keys the public keys that can be used to validate the jlt signatures we'll have to write the jwks endpoint where we will have to return a json with the public keys we only have one so we'll just have to output one public key in a standardized format and then our web application will get that json parsed that and then see if we can validate the jlt with that public key that we received from the authorization server if everything is valid then the token is valid and we can be sure that the user is actually successfully logged in we can trust now this token and the contents within it it is now sure that the authorization server created that jlt and signed it with its private key so this is where we left the body is the token that has been returned from the slash token endpoint so now we need to validate this jlt so what i'm going to do is i'm first going to parse this body of our token is of type oidc token and we're going to json unmartial this body that is the json into this token if there is an error then we're going to return an unmartial error unmartial token error so we know where it comes from and now we can start validating the jlt we're going to return the claims and i was saying that we are going to use the standard claims the standard claims because that's our there's needs to be a pointer our standard claims because that's our function signature but then if you have a look at these standard claims it says that they only support integer-based date fields and singular audiences so what do they mean with that you see here not before expired at expires at only supports integer-based fields which we are only returning so that would actually work for us but singular audiences let's have another look at our token endpoint and here we can see we have these id token and this has a single audience but if you look at our access token here we have a slice so we have multiple audiences and this standard claims can only deal with a single audience so what do they say here in documentation use registered claims instead for a forward compatible way to access registered claims so yeah i can actually just change this into registered claims and we just need to change this function signature and it is forward compatible so our test will still work because here we also still have the subject the subject is still a string but if you need to use the audience it's not just a string anymore and if you have expires at it's also not an integer anymore so this should be a better way of using claims what is then the next step we need to parse these token we have two tokens but let's start with id token parse with claims and now our id token should be in the token variable because we un-martialed it we're going to parse the claims so the parse with claims will have look at the claims that are within the token and put it in this claims variable and then we have the key function and the key function is going to be a function where we have to validate this signature of this jlt and here we'll actually need this public key to be able to validate it how does key function look like jlt key function key function is a function token and interface if we just copy this jlt token and then we need a return save this and then we don't have a compile error but we are not validating it yet what does it return a token and an error I don't think we need the token we just need the error because if there's an error then our token is invalid return nil nil fmt error token parsing failed and the error why it has failed so if if the validation failed then it will throw an error so what do we return here still I think we actually need the token yeah the jlt token so I will call this parsed token parse token claims and then we don't need to return an error just nil and it should be it we then need to start working on this validation code but we didn't implement our jlks URL yet so we'll have to do that first we'll first have to go back to the authorization server implement this jwks URL and then we can write a get to get the public key in this lecture I will show you how to do the jwks parsing so it's standardized so we need to output a standardized json and we will have to do that for every key we only have one key you have the private key in our server struct so as private key is a byte slice it's a byte slice because it is just the contents of this file encryption key.pam and this is a pampformer.file so we'll have to first parse this private key into an rsa private key object and I think we already did that earlier when we generated the token so let's have a look how we did that previously so here we have the private key and we use the jlt parse rsa private key from pamp let's copy that so now we have the private key and the private key also has a public key and this is the rsa public key so we can say public key equals the rsa private key public key now we need to output this jwks URL and because it's standardized I already have it in oidc declared so we have the jwks struct that contains the keys and for every key that is in this array you have an e algorithm use kid and kty key type is just going to be key type so what does that mean what does that mean if you have look at this public key go to definition public key has this and an e and an e here so basically this information is already known for us it's the modulus and the public exponent it's part of the rsa key it's properties of the rsa key so if we can output these in a readable format because this is just a big int we would need to convert this if we can convert this put this in a string make sure that we fill out the fields algorithm and so on then we actually already have what we need we just need to be able to output the public key in an agreed format the format that has been agreed on is to do it in base 64 so we'll have to base 64 convert it so jwks is equal to oidc jwks and here we have the keys which is of type oidc jwks key and here we have one element and this key we need to give an identifier so this identifier is going to be the kid and i'm going to use 0001 as kid because when i generated the jlt in token i specified this header 0001 as kid so this is the id of the key i used to encrypt it it can just be any string you just need to be an identifier what else do you have use algorithm key type algorithm rs256 key type rsa use signature these three are just some informative fields and then now we need the actual public key information n and e re is always going to be the same so this exponent that we are going to use is always going to be the same we can just define it as a static string so this is already convert from the exponent so if you have look at public key this exponent will always be like this so we don't really have to convert it maybe in the future if you have different exponents then you might need another one but for our purpose this will work for n we're going to use a public key n dot bytes and these binds we are going to convert because you cannot just send the binds into this json attribute we are going to convert them with base 64 so we're going to have base 64 base 64 standard encoding encoder string and that should be it now we can convert it json marshal this jwks out an error jlks marshal error if there's an error and if there's no error w write out let's do a go run of the server curl localhost 880 jwks.json uh that looks pretty good with jq so we have the keys the and the e the algorithm to use the k id and the key type so the next step is to go back to our application server do a get on this url parse this back into the jlks struct and then use this to validate our jl t now that we have the jwks endpoint available let's go back to our application server so how does this parse with claims work parse with claims will be executed and then this function will be invoked and we then need to return the public key here it accepts an interface so anything can be returned we should return an rsa public key and when we return an rsa public key then the public key will be then the token validation will happen with the public key so the signature will be compared this is all done in this jl t package we just need to supply this rsa public key to do that we need to first extract this k id so we have access to this token so this token is parsed but not validated yet so if you have a look at token header k id that will be the k id if you don't have the k id then we need to return an error k id not found if we have the k id then we should return the public key let's write a separate function for that so we have the public key that we need the error that it can be returned and we can say get public key from jl ts jl ts URL we need to supply and this k id we need to supply k id is of type interface but it's really a string so we need to still convert this to a string if we then have an error let's just then return the error if you don't have an error let's return this public key function signature get public key from jl ts jl ts URL is a string and the k id is a string what do we return an rsa public key and this will come as a pointer so i'm just going to return a pointer and the error so what do we need to do here to get this public key we need to do a get request on the jl ts URL htp get on the jl ts URL which returns a response and an error if there is an error then we'll return this error and otherwise we want to read the body so we're going to defer the rest body close body error is equal to io read all rest body if there's an error then we return an error and now we can parse the jl ts contents which is a json json unmartial data is in the body and we are going to parse it as jl ts oidc jl ts jl ts again if we have an error then we return an error if the rest status code is not 200 we're also going to return an error because then the json will probably not be valid and we should put that probably in front of the unmartialing we should go right here parse jl ts and now we need to do the opposite of what we did we first need to loop jl ts entry key entry hjl ts.keys so now we have the keys and we need to see if there is a key with the kid range here with the kid that is equal to mykid mykid here that's applied if it is equal then we can extract if we didn't find the kid then we can say no public key fonts with kid kid so how do we extract this again with base 64 standard encoding decode string jl ts key entry and then the n what does this return n bytes error if error is not equals to nil return then an error decode string error but the n is still in bytes and it is actually a big int remember when we were doing this jl qs then we had a public key and the n is in a big int format so we still need to convert the bytes back into a big int n is big from the big package because this is also big big int so we're going to do a big int new int new int accepts an int 64 and returns a pointer to a big integer we're just going to say zero because we actually want to do an n set bytes because we have bytes sets z to that value and then returns z but i don't think we need to return because it's just going to set n to the bytes and then we can return an rsa public key we don't need to pass an error because we don't have an error and n is n we don't really have to pass this e because this e is going to be defaulting to this so not really necessary here we still need to return error let's have a look it actually looks like it's finished now because we did the get request we passed the jl qs we checked whether there was a key id we recorded this string create a new public key with the modulus so we get the public key right here return the public key so that the jl t parsed with claims can validate the id token if we have an error then token parsing failed otherwise we'll just return the r token and the claims as i look at the main function so if you don't get an error here then it is valid let's run the server and let's run the application server and actually just before i'm going to run the application server i'm going to run this test because i have a test to test whether these actually works and it failed verification error token parsing failed rsa verification error so we still might have something wrong i have this jl qs endpoint here that is actually an hp test new server so i have this mock server that i created with a slash token endpoint and a slash jl qs dot json endpoint and here i just create a new key and we create a new token return that solely just a part of the server that is being mocked here and we get an error from the get token from code crypto rsa verification error and actually i had a look offline for a second and it's very logical where i made a mistake because i said earlier in this lecture that we can just use e because it will default to the value that we need but that's actually not true because you see here e is zero and the value that we need if we have another look at our jl qs it's this value and it's definitely not not zero it's not zero but it's actually constant still so if we just go back here add this constant here which you can find on the internet this exponent is a constant or you can probably also decode it from this but if it's a constant anyways we can also put the exponent as a constant and then let's run the test again and the test seemed to work so let's now run the app server and let's get back to our app server login and now we get a token received and also the validation should have happened so if we now go back to our main.go you see the claims now of type registered claims has this subject the subclaim and it didn't throw an error so now we can be sure that the user has been logged in the token is valid and we have the subject what is next let's have a look at our HTTP endpoint so we did the authorization endpoint the token the login the jwks the well known and the last one that we have here is the user info right here we have these claims from the registered claims but it doesn't really contain a lot of information and you also want to keep your jlt quite lightweight in general so what you can do is when you make the initial call which we do here we say scope open id you can also add more scopes you can add a profile or you can add email to have these included into your jlt and then you can pass them in your claims that's one way or another way is that we have also an access token and this access token and this access token can go back to the authorization endpoint and hit this user info this user info will then return us some more information about the user in json format in this lecture i will show you how to build a user info endpoint so this user info endpoint works a little bit different because now we actually have a token the user info endpoint expects that token in the authorization header and that is what you see here below the authorization error needs to contain the token and with the keyword bearer the id token is for the application to validate whether the user is logged in the access token is a token that we can use to make api calls so to make an api call to the user info endpoint we need the access token and the access token also has the audience claim that states the URL of the user info endpoint so we could actually also check on that to make sure that the application doesn't use the id token to get to the user info endpoint once the token is validated then the authorization server can reply some user info in a standardized json you can have a look at the oidc specification document if you want to see the specification of the json it's already something that we have in our users package so i'll be just returning the user here we have our user info endpoint what is the first thing we need to do we need to extract the token from the authorization header authorization header equals our header get authorization the authorization header has a prefix bearer so we can remove that string replace bearer in this authorization header do nothing we can also check whether the authorization header was supplied so if the authorization header was empty then we return an error authorization header empty jwt parse with claims we can use again token string is going to be the authorization header the claims we can use again registered claims you can also use map claims map claims is just a map and then you can parse yourself let's see how far we can get with these registered claims authorization header claims expect a pointer and then again this function signature jlt keyfunk you see i cannot remember any signature i just need always to have a look in the documentation ended and returns a token and an error do we need the token probably not because we can continue with the claims so let's see what we can return return private key are we still to parse a private key private key equals jlt parse rsa private key from pem s private key and this can return error if error is not equal to nil then return the error parse private key error error return private key public key nil no error that should work and then we get the error back from the parse with claims what if there's an error then we have an invalid token parse token error and return so if you come at this point we are sure that our token is valid but does our token have access to this endpoint so we can have a look where it has access for audience in claims audience but what is audience actually audience is a claim string claim string is basically just a slice of strings this type is necessary since art claim can either be a single string or an array so if there's a single string they will put it still in an array when they do the json-martial and that's when I do this they have this martial json and unmartial json which are the custom functions that are being invoked when they martial or unmartial json so actually I just need the range keyword that should work and now I have an audience found is false if audience is equal to the config URL was the user info then found is true and if found is false then we didn't find this and then we can say return error token has incorrect audience and we can even output the audience just in case that we get an error that we can easily debug it so what's audience of this token we can join this claims audience together with a comma so now we know for sure that this token has been issued using our private key because we have this validate function with our public key we are sure that the token has access to this endpoint because we checked the audience now we need to return the user the user is the subject let's have a look at our users package we did the authentication we return the user these are subjects so we can compare our subject from our token to the subject here and then return the user the user has the json sub name given name family name preferred username email and picture which is our standardized response that we need for users in for user in range users get all users if user sub equals to claims subject and let's also check if claims subject is not empty just to be sure it's empty then return error if something goes wrong in our in our authorization server and we would issue a token with an empty subject we don't really start comparing this so subject is empty just as a safety measure if we find it what are we going to do do json marshal this user and if there's an error then we're going to return error and otherwise we're going to write the output and if you didn't find the user that if you didn't find the user then we do a return error where we say user not found return we have a user info test that we can use to test our code that we just have written test user info and we get an error you get status code 400 power stock and error keys of invalid type let's have a look keys of invalid type and i guess this should be a pointer to the rsa public key because otherwise it probably doesn't check for both the rsa public key type and the pointer type and now it is working code user info json the subject name the given name family name preferred username email and pictures empty so this is the user info endpoint you can have a look at this test to see what is actually necessary to go to the whole flow so this is using the htp test package to do requests on the authorization to do the login flow and so on all the way until we hit this user info endpoint we are now going to do the same but in the application server in the next lecture so now we will need to hit this user info endpoint and see if we can display this to our end user so this is really going to be our last step for our oidc flow our first simple flow that we have in our oidc server our authorization server we're just going to hit this user info endpoint with our application server to test whether everything works and then we should be able to use this authorization server as an authorization server also for other applications that support the oidc flow let's have a look at this main so in this main we have this callback and then we have access to our token maybe let's return also the access token or let's just return access token and not the id token so let's copy this access token claims access token parsed access token access token also has the kid so we should be able to verify that and then let's just return this parsed access token and together also the parsed token or let's not do that because we have to change too much i'm just going to only return the access token because you are not even using the identity token we will just verifying it parsed access token save access token so now we need to do a call and we need to change the request headers so our call will look a little bit different new requests it's a get request the url is going to be on discovery user info endpoint and then the body it's going to be nil this is going to be request if error is not equal to nil return an error new request error request header add authorization in the authorization we have the bear and then the access token access token raw is a string so this should be the access token now we have the request we still need an htp client htp client and we can do an action using a request and this gives us back the response just like we would do htp get and post do request error defer res body close and let's get the body read all res body read all error and i just print out the body as senate token received user info and then the body i'm gonna make this fmt sprint f comma here res body like this we still have an error somewhere we are not using the claims save this run the server run the app server this is from previously state mismatch error so if we try to refresh it it doesn't work so our authorization server is doing this correctly we cannot use our previous state and our previous code to get a new token let's authenticate again and token received token validated we went to the user info endpoint and the user info endpoint gives us back this subject the name given name family name and so on so this is now the whole flow that we completed the authorization the callback we have created every endpoint that we need so if you want to plug in now another ydc compatible application that should work we might not have implemented the complete protocol so here and there you might have to add something for example if the implementation expects that it would receive some more claims if it adds the profile to the scope then you would also need to implement that this is a basic or dc server but it's a great starting point to extend it if you need any of those features because our default implementation is actually done at this point the application server is also very basic of course because we are not really saving this token or anything right here so what you could do is you could change the application server to store this token somewhere locally so that per user you can then access their tokens you can then use the tokens for authentication validation is user authenticated or for authorization what else does exist in this token maybe the user is in some group that has then special access on the application server and also you have the access token that you can use to make api calls to the user info but maybe to another application server that is running so if you then need to make a call to another application server you can then use the access token those tokens will expire so within an hour this token will not work so you will either need to authenticate again or implement the offline access that means that you need to have code where you can then refresh the token so if you have a valid JLT you can then get a new JLT with another 60 minutes as long as you have a refresh token we haven't implemented that but that shouldn't be too difficult to implement at this point also some authorization servers they don't really look at the offline access scope they just give you automatically a refresh token it all depends you have the reference documentation of ORDC everyone can do the implementation some implementations are not completely following the reference documentation but that is often okay because the standard also leaves some room to do your own implementation it kind of gives you a minimum that you should implement but then for example the user info endpoint could also return us a few more fields that is not really specified in this standard so that is it for our minimal authorization server if you would find mistakes in there or you want to do some improvements all PRs on my GitHub are welcome if they are adding functionality I might not immediately merge them with the solution that we have but I might for example create another directory in my GitHub repository with a v2 where we can have some improvements that were out of scope for these lectures now that we have an ORDC compatible authorization server we can start adding applications that support ORDC there are a lot of applications and SaaS applications that support ORDC often next to SAML there's also companies that can act as an ORDC provider itself like Google, Apple, Facebook those social media logins have ORDC capabilities you could either use the authorization server and trust their token or write an integration to validate a successful social login and issue your own token with your own server often plugins are available to existing tools and software to implement ORDC in the next lectures I'll show you the ORDC integration with Jenkins which is a popular CICD tool and AWS I am Federation with ORDC in AWS will make AWS trust our ID token to issue access keys to our users so within AWS we can do federation and we can say that if a user can log into a specific app then that user can be granted AWS access keys to be able to use the AWS services using the AWS API in this demo I want to show you that our authorization server actually works with real world applications I'm going to set up a Jenkins server and I'm going to change the authentication part into OpenID Connect or IDC and I'm going to use our authorization server for that so Jenkins will be another application for our authorization server let's first start to run the server and I opened already the config here because we will need another redirect URI here so we could actually create another app if you want or we could just reuse this app the smartest thing would actually be to create a Jenkins application client ID one two three five secret is secret the issue is the same and the callback will have to change but I don't know yet what the callback is we'll change it then we need to run a Jenkins server and we can do that using Docker so if you don't have Docker installed it's best to install Docker for Windows or Docker for Mac and then you can use Docker commands there's an image Jenkins slash Jenkins and it has the LTS tag and this will launch a Jenkins image I'm just going to add a few flags I'm going to add a volume the volume is called Jenkins I'm going to mount it in var Jenkins a home and I'm going to expose a port 80 90 and I'm going to map it to 80 80 so 80 80 on Jenkins is going to map to 80 90 on my machine minus it so they can hit control c when necessary and then maybe I can also add minus minus RM so if I quit my container then it will be automatically deleted it will not delete the volume so we can then still launch Jenkins later on you can also give the name name Jenkins if you want to find it easier in the process list and then actually I need just docker run because we are running Docker run Jenkins Jenkins with all these flags and then we can start it so you have to wait a few seconds and it says Jenkins initial setup is required an admin user has been created and a password generated so please use the following password to proceed so now we can go to localhost 1890 and then we should see this screen unlock Jenkins can put this password you can still find it here if you didn't see it in the output and then we can install the suggested plugins or select plugins to install I don't really need any plugins I will just install plugins later on and I can create a user so let's do that Jenkins URL and we can start so we have one user my adword user but now we are going to configure oidc so I first need to install the oidc plugin under available plugins open id there's two plugins we can use but I checked and this one has more installs so most likely this one is better install and then we can go back to the dashboard manage Jenkins configure global security so security realm Jenkins own user database or login with open id connect client id we then need to enter one two three five client secret secret configuration mode automatic localhost 8080 well known open id configuration and this will actually not work because now we are in our container so we would have to reach our whole system which we cannot do but there's an easy solution for that and we'll also need it in the next demos you can install something called ngrok ngrok serve web commands with one command you can sign up for free but you can also just download it and you don't really need to sign up macOS brew install ngrok for windows you can download the zip file or do it with chocolaty chocolaty is a package manager to easily install packages or even with docker you could do that it looks like i'm going to use the macOS version so i'm just going to open another window here i have ngrok already installed and i'm going to do ngrok htp 8080 and that will give me an endpoint this endpoint and this is a public endpoint that will map to my localhost server that i should be able to use here and it's also htps so it's encrypted this works and now what i should actually do is to also change a configuration file so i'm going to put this in place and then stop the server start the server again and then in advanced you can also have some more advanced options so for example the full name field for me is going to be name so Jenkins will also hit our user info endpoint to get this extra information we also have an email field i think that was email i could have a look if we have look at users we have here email i could enter it there as well so here we have name sub email so let me just add email here and you could also add a groups field name so if you add a groups field name that means that it's going to expect an area of strings and then you can have groups and the benefit of having groups is that you can then download another plugin for authorization matrix authorization then you could specify groups and then you can match groups to specific privileges so now we logged in users can do anything but if you want more granular access you could add groups and then use the authorization plugin in Jenkins to give more granular access to those groups so i'm going to save this then i'm going to log out so here we are the adward user now i'm going to log out i'm going to go back to localhost 8090 you might get this warning just because we are doing a redirect then you just have to press this button redirect uri not white listed because i didn't know the exact uri so i'm just going to copy paste it from the url and then in our Jenkins application i'm going to add this as redirect uri refresh this oh i still need to restart our server refresh this and then we have our login form i'm going to log in and then i'm logged in welcome to Jenkins who am i now here's my full name and i'm the Jenkins user id 9999 because that's my user id so if you have a look at the people here we now have the users this is the user from open id connect and this is the user that we added at the installation and then you click on my user configure then we can see the full name comes from the authorization server and also the email address comes from the authorization server so that was nicely filled out so we can even have more mappings to fill out more information if you want that's the benefit of having an authorization server it can distribute user information to your application servers so that's it for Jenkins there is always a possibility that you try out an application and that our authorization service is not immediately working with it then you just need to have a look at the flow that it is using you have to make sure that all the OIDC capabilities that the application needs are also implemented because we might not have implemented every single step or every single capability when preparing the ALS OIDC lecture where we will get ALS tokens based on our token that we get from our application i realized that our discovery endpoint is missing a few attributes that we should return otherwise this is not going to work because ALS IM identity and access management is actually checking for a few more attributes that we don't have so I have those added in the types it's id token signing algorithm value supported claim supported and subject type supported so we need to add those otherwise the next demo is not going to work so we're going to have id token signing algorithm supported which is rs256 then claim supported also a string slice and these are the claims that we are returning so we have sub and we can just have a look at our token endpoint we have issuer sub audience expiration issued at and not before and then lastly we also have subject types supported and there is a mechanism to hide some privacy sensitive information so the only thing we need to do is say that we only support public we just return the subject the other thing we need is when we are going to use the app server we are only replying one token and we are going to need both so I'm just gonna make an array of this and then here we have the parse access token right here we have the parse id token and I'm just going to jwt token going to add both of them first id token and then the access token parse the id token and I need another column here save this go to the main so here we have both tokens and tokens the second one is the access token and I'm just going to print on the console the id token because the id token is the one we need the next demo tokens raw so that's it we should be able to run the server again and also maybe one last thing to mention from this discovery endpoint if you want to know more about this discovery endpoint you can have a look online and just type in open id configuration endpoint and you will find some information for example I found this held up wiki and this held up wiki explains every single attribute that you can have so here is an example and here at the bottom you actually have what attributes are required so the issue is required the authorization endpoint is required which one is optional and which one is recommended so we have the username for endpoint which is recommended but not required but then we had some other required missing which didn't work very nicely with alias so this information is actually very useful when creating this open id configuration endpoint in this demo I will show you how we can use our OIDC authorization server to get alias access tokens we can configure within alias im identity and access management our OIDC server that way every user logged in into our authorization server could potentially get alias credentials from alias im let's have a look how this would work first we need to again set up our ngrok tunnel so I'm just going to run the server first and then open another window this is the same as I did in the previous lecture if you didn't follow the Jenkins lecture you just have to download ngrok from the ngrok website or with brew any type ngrok hp8080 and that will tunnel port 8080 from your local host to a public available hostname this is our hostname our server is running we just have to make sure that we update our config file as every time you use ngrok this hostname will change we then need to restart our server and then we should be able to use this hostname in alias so this is my alias account it's a sandbox account it's empty I just created a new one and we need to go first to IAM manage access to alias resources and here we have zero users so we only have our root user and we are not going to create a user we are going to use our identity provider so we click on identity providers and here we can add a new provider use an identity provider IDP to manage your user identities outside of alias but grant the user identity permissions to use alias resources in your account so you first add a provider and here you can choose between SAML and open id connect so in the first lecture I was explaining you SAML and OIDC where SAML is the older standard and open id is a newer one and you can see that indeed SAML is still used in a lot of places in the past even only SAML was used in alias and then only later they supported open id because also when alias came out the open id standard didn't exist yet we are going to choose for open id connect and then we can provide this URL I'm going to provide my ngrok URL and then you can click on get thumbprint this thumbprint is from the CA certificate so the CA validity is until 2024 so ngrok is configured with HTTPS there's a certificate in use the certificate I actually checked is from lads encrypt it just to make sure that alias validates our certificate it's not going to do it on the service certificate because a service certificate typically is only valid for a couple of months or for a year so it does it on the CA and the CA is typically valid for a couple of more years so we are now 2022 so it's valid for two more years now we can configure the audience and audience in our id token is the client id so that's why we have to also supply the client id to be able to log into alias we cannot use the access id it's going to check the audience and the audience needs to be equal to the client id so I'm going to use the client id from our first application server 1234 and then I'm going to add this provider so the provider is now created and now we can link a role to this provider so we can click here and assign a role to it I'm going to create a new role and you could say that whoever has access to our application server our first application server has access to the complete alias account so admin permissions or you could say whoever has access to this account has a specific subset of permissions I'm going to add as three permissions just as we are working with some kind of development server we just created the server so if something goes wrong then at least we don't have admin privileges so this is our identity provider audience is 1234 and alias calls is the audience because the audience is equal to the client id but we always call this a client id and not really the audience so in the id token audience is equal to the client id and that's why they call it audience here permissions so here we could give administrator access or I'm just going to do s3 full access tags if you want to create tags review oidc demo s3 role I'm going to call it create a role and now we can assume this role using oidc using our oidc token I need this errand because that's what I want to assume and I will have to use the alias command line utility so if you don't have installed yet you can install it from the alias website or again with brew or with chocolatey so that you have the alias command available then we will also need the client token so we need to log in to our application and we have to make sure the client id matches so the client that we entered matches with our app one so I'm going to log into app one and that is going to give me the id token so here we have app one I'm just going to start our application server so this oidc endpoint can still be local host it was just going to verify this token it doesn't need to have access to our application server and now what's going to happen here I'm going to see the id token in the output because I added this fmt printf here id token token zero zero should be the parse id token okay let's try that out local host 8081 login my login and password token received and let's just make sure that I copy again this arn and then we can try to log into alias and get the tokens let me maybe also create an s3 bucket so that we can do an s3ls to list the buckets and when that works I'll be able to see whether whether the tokens actually work my test bucket I'll just add some random string here because we know it might already be in use because it needs to be unique within this alias region so just have to make sure that it's unique enough because my test bucket will probably already exist so I have a bucket so I'm going to try to assume this role here and here you can also see that there is this trust relationship where we have this audience needs to be equal to one two three four so only the tokens from this app server will work on our oidc provider that is what alias going to check is going to check this token see if the signature matches with the public key and if that matches it will accept the audience the audience is equal to our client id if this audience is one two three four then I am granted access here is the id token so let me just open another window so our role role eran is this one don't want to lose it and our token is this one so I'm just going to say token equals and then here I can do echo token echo role eran if you're if your windows you can use set I think or you can just copy paste it in one string that's also possible because it's just easier for me to work but you could also just enter everything in one string so you need to have the alias account but you don't need to be logged in alias stls unable to locate credentials so I have no credentials and now I'm going to try to obtain credentials and I'm going to do this with alias sts assume role with web identity so I think if I just add help to it then I will get the help function and if you scroll a little lower it will show us the arguments the role eran check we have it role session name is just an identifier so could be our user for example it's just a value it's not being checked on and then the web identity token so this is what we need to be able to get a token so I'm going to do alias sts assume role with web identity role eran is our role eran web identity token is our token and role session name is just going to be my name at the word that should be it really let's try it out if it works or before we try it out let's just verify our token jwt.io I'm just going to paste this token here so that if you have troubles yourself that you can have a look at my token so I have the algorithm kid and the audience is important one two three four this is the client id because this is our id token the kid is going to be used by alias to get this public key from our jwks endpoint and to validate our signature right here so once the signature is validated it can be sure that our authorization server issued this jlt so let's try and we get the credential now you can actually see using ngrok the calls that happened so these calls just happened here it went to the open id configuration and it also went to the jwks json to download the public key and this is when I logged in I did the login and then here are some other requests that either me or alias did so let's go back so we now have these access keys and these access keys we could configure in our dot alias slash credentials or we can just configure them as environment variables and see if we can do s3ls so there's also an exploration so what time is it now here it's 1108 and this is udc so this must be valid for an hour let's try to configure them so if I do alias access key id equals to this secret alias secret access key equals to this part and then the alias session token equals to this part and then I don't really need to blur any of this because this will be expiring in an hour anyways alias s3ls and I get my test bucket so you can see that with our id token we can get alias credentials that are valid temporarily assume this role right here and then use it to access alias and we didn't even have to create a user on alias this is also called federation in alias so if you would like we could potentially write an application a go application that lets you do the authentication with a user a password maybe even with mfa and then does this sts assume role with web identity api call to get yourself credentials admin credentials normal credentials so that you can get access to the alias api and this is actually the same mechanism that alias uses for pods in kubernetes so if you use the kubernetes service on alias then also every pod will get a jld and then there's also an environment variable that is exposed to the path where this token is and the alias sdk will automatically read this token and then will get automatically the credentials let me just have a look what the name is of this environment variable if you're interested in it so here we have the configuring the idles sdk for go v2 and within kubernetes or if you would be writing something where you would also use jlds then if you use the load default config there's always a path that it follows so it actually says here when you initialize an alias config instance using config load default config there's a default credential chain environment variables the one we used right now so if you configure those then it will automatically find your credentials or also the web identity token so if you have configured the alias web identity token file and your token is in that file then you can also just configure this environment variable and then the alias sdk will automatically go to the file read the token and get those variables if those two are not found then it will also have a look in the alias folder in credentials and also in the alias config so there's a certain path that it follows so if you want to make sure that your credentials are properly configured just have a look at this documentation and make sure that you either supply one of these as paths for alias to find your credentials so this is it if you have any problems with rdc and alias have a look whether your discovery endpoint is okay have a look whether your jlds endpoint is there whether the flow works with the normal application whether your id token is valid and then it should work if it still doesn't work for you feel free to reach out to me directly and i can always help you in this section we are going to talk about tls tls stands for transport layer security and is used for data encryption web encryption typically uses tls to encrypt communication between client and server tls is a successor of ssl secure socket layer the default port for unencrypted htp traffic is 80 and a default port for encrypted htps traffic is 443 tls itself is not an encryption algorithm with a protocol to negotiate and agree on a common set of encryption and hashing algorithms called the cipher suite with tls enabled the htp server offers the client an x509 certificate which can be validated by the client to ensure the server can be trusted the hostname of the server will be included in the server certificate the server certificate will be signed by a certificate authority abbreviated ca if the client can validate the server certificate we can trust the server and this is what exactly happens when we go to a secured website using htps in the browser to be able to validate the certificates we'll need to always have the certificates of the certificate authorities that can sign the certificates they're also called the root certificates browsers typically have this list built in and within go it'll also look for those files in hardcore the system paths to be able to validate certificates so these certificates are provided by the operating system so on the linux system they will be different than a window system or a macOS system and with macOS or linux for example it will be the operating system itself keeping them up to date so go will just look into a few directories to see if it can find those root certificates once it finds one directory with the root certificates in it it will stop looking and it will use that directory so with the browser this is all pretty straightforward you're using this every day where you go to an encrypted website the validation happens because your browser has those root certificates and you can automatically trust the server if a certificate will be expired or the hostname would not match or the signature cannot be validated you would typically get an error which sometimes happens on websites that don't maintain their certificates what i just talked about this is our client server communication where the htp server offers the client a certificate that can be validated this is called one-way TLS you can also set up two-way TLS or mutable TLS abbreviated mTLS in this scenario communication can only be established when the client also has an x5 or 9 certificate so this you will typically not see with your browser because then your browser would need a certificate to be able to access a website this two-way TLS is used often in server to server communication for example to secure communication between microservices in the following lectures i'm going to add TLS support to a simple gohp server there are multiple strategies to implement TLS using a self sign certificate we will issue the certificate authority certificate ourselves so only someone who has a specific ca certificate will be able to validate our server certificate using a real certificate issued by a company that can sign with a root certificate so companies like the dessert geotrust rsa global sign they own these root certificates and they can issue a certificate for you that is signed by one of their root certificates and those will then be valid if you would use a browser and visit your website with that certificate installed because your browser will have these root certificates built in and is able to validate the signature of this server certificate and also using let's encrypt a non-profit certificate authority so this is kind of a third option because the second option the certificate issued by a company you most likely will have to pay this company because they need to verify that you are the real owner of this host name of this domain name and with let's encrypt this is actually free it's a non-profit so you can get a free TLS certificate with let's encrypt and they will have an automated procedure to get you verified in the next lecture i will explain these strategies in a little bit more detail and then we will start implementing a self sign certificate all these approaches can be used for one way TLS for two way TLS a self sign CA is common but other approaches would also work so for example within Kubernetes you have a lot of two-way TLS because you have a lot of services talking to each other and you need to be able to trust each other within microservices you have two way TLS with VPNs you have two way TLS one way TLS is what you see every day in your browser and two way TLS is probably something you have less exposure to when you have two different services talking to each other so every approach can be used for two way TLS as well although self signed CA with two way TLS is a bit more common than using real certificates although it is still possible to do two way TLS technically with a real certificates or even with let's encrypt let's go over the TLS strategies we will look at the self sign strategy signed by a root CA and let's encrypt first the self signed CA this will also be the next goal demo that I will show you it's using a self signed CA in that case we're going to have a server a client and only the server is going to have certificates not declined because it is one way TLS and this server certificates need to be signed by a CA a certificate authority so that the client can validate whether the certificate is real because it is self signed we are also going to be the certificate authority so we're gonna have to create a certificate authority certificate and a certificate authority key with this key we can actually sign one or more certificates so here we only have one certificate but we could be signing a lot of certificates we only need one CA to be able to sign multiple certificates once we have this setup we can use the certificate authority key to sign the server certificate the client can then connect to the server using TLS the server certificate will be offered the server key will not be offered because the server key is secret to the server and the client can then also download the certificate authority certificate to validate the server certificate because this is not a root certificate the client is not going to have this bundled in the browser or bundled in the operating system so you'll have to provide this CA certificate file to the client to be able to validate the server certificate if we maintain the client for example the client's also a go program or it is curl or it is our own browser then this setup would work because we can have this CA certificate installed where it wouldn't work is if you would have a production server a public production server and we would offer any client that will connect to our server any browser this certificate where they don't have the CA then they would get an error because they don't have this CA certificate and that's why all the servers that we connect to in a real world scenario are actually using one of the root certificates so root signed CA is next where we still have the server the client the server certificate and the server key but the client in this case has the root certificates available to be able to check the server certificate it just needs to be signed now by a certificate authority company this certificate authority company we have the certificates of this certificate authority company but not the key so we cannot sign any server certificate ourselves we don't have access to the CA key or else everyone could sign any certificate and this whole validation process would just not work we all agree to trust these certificate authority companies to only sign server certificates after they've validated the host name in this server certificate so they will go and send an email for example to the email attached to the domain name and ask are you the real owner can you verify that you are the real owner and only then they will sign your server certificate so how does it work well you need to first give an unsigned server certificate to this certificate authority company this unsigned server certificate is in the form of a certificate signing request or abbreviated csr so you basically give your certificate that you generated using your server key and the certificate authority company is going to sign this for you and give it back to you so now you have a signed server certificate and then the client can connect using tls to the server will receive this server certificate and will be able to validate this server certificate because it has the root certificates without the certificate authority companies in there to be able to validate this server certificate so you can imagine if you have a very old operating system or very old browser that is 10 years old and hasn't been updated then actually those certificate authority certificates or root certificates they expire and when you then visit a server you would get an error so if you for example install a very old browser or operating system that is 10 years old you will see that those root certificates are not valid anymore and you will get an error when you just browse to some common websites and then we have let's encrypt and let's encrypt is very similar to the root certificates because let's encrypt is also a company that is included in the root certificates the difference with let's encrypt is that it's an organization it's a non-profit and they don't ask money for a tls certificate we still have the server and the client the server certificate and the server key the root certificates that has let's encrypt in it and let's encrypt itself the company we still don't have access to the c a key because that is managed by let's encrypt what let's encrypt is going to do is it needs to be able to validate whether we really own this domain name let's encrypt is validating our website using this automatic certificate management environment let's encrypt will connect to the server that needs to be publicly available and will go to a specific path that you can see here it's dot well known slash ace me challenge slash token and this token is something that let's encrypt will give you if you start the procedure it will see whether you really own this domain by putting something unique on your domain name that can be verified by let's encrypt so let's encrypt will give you a random string you put that random string on your server if you are able to do that then let's encrypt trust that you own this server that you own this domain name and then it will then sign your server certificate here again you need to give an unsigned server certificate a csr certificate signing request to let's encrypt so that it can sign your certificate based on this certificate signing request you then have a service certificate that is signed by let's encrypt and the procedure now is the same the client connects with tls the server certificate that is signed is offered and the client can verify it using the root certificates that includes also let's encrypt let's encrypt is actually the newer strategy compared to the first two because the first two already around for a very long time and let's encrypt is a new approach that came into existence so you don't have to pay these companies always for your tls certificates let's encrypt is very popular so there's a lot of websites that use let's encrypt so they don't have the cost of paying for every tls certificate it might be just a bit harder to get a certificate because you have to use this automated process with the other companies that sign your tls certificates there are more options to do the validation process but if you can use this automated validation process it will end save you some money and it will also save you time to renew the certificates because you can automate your renewal as well one strategy that i didn't cover yet is two-way tls so the mutual tls so with the mutual tls the client also has a certificate so how does it look then we have a service certificate and server key and the client certificate and the client key we have a certificate authority certificate and a certificate authority key so in this case we have self-signed certificates because we will also be the certificate authority with the certificate authority key we can sign both the client certificate and the service certificate and then we can distribute the certificate authority certificate to validate both the client certificate and the service certificate so the client will be able to use the ca certificate to validate the service certificate and the server will be able to use a ca certificate to validate the client certificate. So the client makes a TLS connection. The server will be able to validate whether the client has a certificate and whether the certificate is valid. And the client can do then the same thing. So the benefit of Mutal TLS here is that you can have a two-way trust. In one way TLS, the server doesn't know anything about the client. In two-way TLS, the client is also identified by client certificate that is also signed by the certificate authority. So the server also knows that the client has obtained a certificate that has been signed by the same certificate authority. Like I said, you also have variations on this, where you have two certificate authorities, or you can also use a root certificate. In the next lecture, I will show you how to do a one-way TLS setup with an HTTPS server in Go. So it will be a very simple server using the self-signed strategy. This is the TLS start project from my Github repository. And this TLS start project, I'm going to use to show you how to create a command line utility. A command line utility to create a certificate, a CA certificate first with the key and a server certificate. Because in this TLS start, we have a test server. And this test server is going to launch an HTTPS server. So if we have a look here, so we can run this by Go, run a CMD test server main.go. We have the main function. And we only going to handle slash the index page. And instead of listen and serve, we are going to use listen and serve TLS. TLS needs the address, which can be 443 or 8443 if your port 443 is blocked by maybe not a program already. We need a cert file and a key file. And it's going to be the server certificate and the server key. So if we are going to run this now, go run, CMD test server main.go, it will complain because we don't have this server certificate and server key. This is a server certificate and server key that we still need to create. And how would you create those in the past? Well, you have the open SSL command line utility, but we don't want to use it open SSL utility, we want to write our own command line utility. And our own command line utility will generate this CA certificate and key, and we'll sign the server certificate and key, just as I explained in this previous diagram. Just as a refresher, this is the setup we are going to build. So the server here on the right with the server certificate and server key, that's what you are going to pass to this function to start our server. But first, we need to create the CA key and certificate to sign our certificate. We can then have a client that loads the CA certificate, then connects to the server and can then validate the server certificate using the CA certificate. Our client can be a browser can be another goaling program, or can be something like curl or postman, I'll be using curl. So this is our server. And we just want to write a command line utility. So we are going to have a TLS command. So TLS command, go run TLS main dot go. And nothing will happen because we don't have any code in there. But that's how we're going to run our TLS executable. You can also build it obviously, and then execute like that. So once it's ready, you could actually make the binary and use it even yourself to create certificates, or even extend on it, because our functionality will be pretty basic, but you could still extend on it. Because the open SL command line utility is quite extensive, you can do a lot of things with it, we will just do a subset of that, we will be able to create CA certificates and sign them. But compared to the open SL utility, it's not a lot. So this main goal will load the PKG CMD package, PKG CMD. So that's where we're going to write our command line utility code. So we have the root dot go and root dot go, we have the execute function. We are going to use a library for that. It's a popular command line utility library. It's called Cobra. So we'll be using Cobra for the command line utility code. So we don't have to write everything ourselves. Cobra is used by popular tools like Qubectl. So it will look very familiar if you already used Kubernetes at some point. So this in CMD, we'll have our command line utility codes. And in the third package, we'll have our certificate codes. So if we are going to write codes for these x five nine certificates, we'll do it here. We need to create a CA certificate and create a server certificate. So the server certificate is not very special. It's only the CA that is special. So we can have a function for the CA certificate, and then a function for a regular certificate. And then later on when you need to create a client certificate for two way TLS, you could reuse this function. We have the PEM dot go and the PEM dot go just has one function, PEM two x five one nine, it just reads input in binds, which is a PEM format file, and then we can decode it and parse it into an x five nine interest to help a function right here that you don't have to write yourself. In times, I have the times, the CA cert, the cert and the cert subject. Why do I have already those because we are going to use a conflict file. And this conflict file is something I will just supply to you. It's called till as a demo here. And here we are going to define the information that we need to create our CA certificate and our service certificate. So we have a CA certificate. Every certificate needs a serial. How long is it valid valid for 10 years? And this is a subject, every certificate, the CA certificate and the service certificate, they have a subject. They have a country, organizational organizational unit locality, and a common name. There's even some more information that you can give that you will see in these types of go. So you see here, the subject is a little bit longer, there's some more attributes that you can add here. The common name in a certificate is either just a name like CA certificate to show someone looking into the certificate that this is a CA certificate, you could even add the name of your company. But then, for example, if you are going to use certificates, server certificates that we are going to use on websites, then the common name is going to be the host name. So here we have common name is go demo local test dot me, and local test dot me, and all the sub domains of local test dot me, they actually resolve to the IP address 127001. So we can use this address, because it will resolve back to our own machine. And that gives us a DNS name that we can then use to connect to in our browser or call. Our service certificate also has these other subject lines. It has a sale valid for years. And you will see that the CA is typically valid for longer than the certificates itself, the service certificates. Its best practice to rotate them once a year, for example, could be earlier with let's say crypt is going to be earlier with root sign certificates you can often choose. We are choosing here for one year, but it could be as well two or five years or something that you typically want your CA to last longer than your certificate. So if you pick 10 years here or 15 years, you will also have to increase this one. And then the last one is that if you want to have more DNS names, you can also use DNS names. And then you will have your common name, plus more DNS names. For example, if you are using your own domain name, and your own domain name is called local test of me, then for example, you could have local test of me, and then the DNS name could just be the root of the domain so that you cover both of them. We are just going to use code demo, but feel free to use any name that you like. So this is the last demo, we'll still need to parse this. We just have the types available, so we don't have to create them. Here's the YAML annotation, so that we can un-martial this with the YAML. We'll do that in the root package in the next lecture. It's one of the first things that we'll do after I explain you the basics of Cobra. So next lecture, we will start with Cobra. This will go in the CMD package, then the certificate code will go in the search package. And then we also have the key package. So every certificate needs an RSA key. And because I already went over RSA keys in our previous section of SSH, because SSH is also using RSA, I already have this code prepared. So the code is very similar to the SSH code. So if you want to know the details of RSA keys, I would suggest to have a look at the SSH lectures. We are just going to use these functions. It's actually very simple. We have to create RSA private key with a search on length, which will use generate key and reply a private key. With this RSA private key, we are not that much, we need to transform this private key to PEM format. So this is what the RSA private key to PEM does. It takes a private key in the private key format, and returns a PEM block with RSA private key. So then we can save this in a file. And then we just have a save function create RSA private key and save, which will create the RSA key with permission so that only the owner can read it. It will encode it using PEM and then save and close this file. And then we have the function to read it back. So if you have a file in PEM format, we can use a private key PEM to RSA, which will then PEM decode the RSA private key and put it in the RSA private key format. So for that, we use the parse pkcs1 private key function to convert it from a PEM format to an RSA private key format. If we ever need the public key, the public key is accessible within this private key as well. So these are the functions, the RSA functions that we have to create a new key and convert between PEM and RSA format. So that is it. I also added this git ignore to make sure that we don't commit any PEM CRT or key file to GitHub. And then we also have the go mod file, where I define the module name, and I also replace the mock version from 143 to 144, which you probably already have seen in one of my earlier lectures. There's just something wrong with this 143 version. So it's just saying if you come across this 143 version, just replace it with 144. So this is it for the TLS start program. In the next lecture, I will start working on this program starting with Cobra. If you need any of the solutions, then you can have a look at TLS demo where you'll find all the code that has been written. In this demo of the TLS command line utility tool, I'm going to use Cobra. Cobra is a project that you can find on GitHub. So it's github.com SPF 13 Cobra currently Cobra is a library for creating powerful modern CLI applications. Cobra is used in many go projects such as Kubernetes, Hugo, the GitHub CLI to name a few. So it is actually quite popular because Kubernetes is a quite popular project, and it is using Cobra. So what's so good about it? They have an easy way to create subcommands. For example, you can do app server, app fetch. So it's pretty easy to use. You can also nest your subcommands, we can have in our case, TLS create, TLS create key, TLS create CA TLS create cert. So those are all subcommands that we can create in a nested create command. So let's have a look how we install this. Go get GitHub.com SPF 13 Cobra at latest. So I'm going to copy this already. And then we have the user guide here. So if you want to know a little bit more about Cobra, I would recommend you to read their user guide. It's not very long. So what we already did is we created this CMD directory in our PKG directory. And this is where you typically put your goal files for Cobra. Our main.go looks exactly like this. We have a main with CMD execute. So the main is very bare, it serves only one purpose to initialize Cobra. So we're going to initialize Cobra in the execute function within our CMD package. They have Cobra code generator if you want to use it, but we are not going to use it. We already have some code ready to go. The first goaling program that you would make is for the root CMD. Ideally, you place in root.go. So that's what we are going to do first. That's where we have our execute function. So let's try to copy this code and see what happens. We'll replace this you go by our TLS explanations. So first I do the go get. And this is going to download Cobra 150. It's updating the go mode file. And now I can start writing in root.go, the first lines that are going to use this Cobra package. So I'm going to copy this and just replace this, save this so the imports are correct. So we imported Cobra. This is the root CMD. And when we do execute, it will execute the root CMD.execute. If something goes wrong, it will show an error on SCDR. So I just want to replace this, the use, the short, the long, which is the command and the explanation TLS. TLS is a command line tool. Or it could be utility or interface for TLS. And then we have a long explanation. TLS is a command line tool for TLS, mainly used for generation of certificates, but can be extended. I think that's fine. Let's just have a look what this does. So let's run our go run CMD TLS main.go and it doesn't do anything yet. Because we are just hitting this do stuff here. But because we already initialized Cobra, we should be able to use the help function. And this is what is nice about Cobra. Now that we initialized our root CMD, it already has a help function. TLS is a command line tool for TLS. And then you see can put some nice text here usage TLS flags, there's a help flag, and now we can start adding commands. Every command can go in a different go file, and we just need to add more of these Cobra commands. Once we tie these Cobra commands together, they will show up in the usage, we'll also be able to add flags and then they will show up in the flags. So this is a very nice package that will make it for us very easy to write a command line utility. So one last thing that I want to mention here is that we have this execute function, and this execute function happens on the root CMD. But the root CMD is actually declared outside our function. So the scope of this variable root CMD is not only within this function, but within the whole package. So once we create more go files, we'll also be able to access this root CMD. That way we'll be able to tie all these commands together to the root CMD. And that's how then the root CMD execute will tie everything together. The root CMD execute will use this root CMD, everything will be tied to this root CMD. And that's how this Cobra package will be able to find the link between all these go files, and then we'll be able to show the commands that you can execute and the flags that you can use. So how to add flags and commands will all become more clear in the next lecture. This was just a simple introduction to the Cobra package. In the next lectures, we'll be adding the config file and more commands to be able to create our keys, CA and certificate. Now that we initialized our Cobra package, let's try to parse this config file. So this config file describes a certificate, our authority certificate. That's a serial valid for years in a subject. And then it has certificates that are going to be signed by this CA certificate. So search is a map, because we have here a key, and we can have more certificates that are identified by key, so that we can have one or more certificates, or even zero. That way we can have now one certificate, but if you later want to add more certificates, we can add more certificates. So the first thing is going to be to add a flag in our root.go to allow the user to supply a config file, just the path to a config file. And maybe we can even put tls.yaml as a default, so that if you don't supply anything, it will automatically look for tls.yaml. So how do we do that? Let's maybe have a look at the documentation of Cobra. So create root cmd. That's what you already did. We have function execute. You will additionally define flags and handle configuration in your init function. So remember that when we have an init function, that function will be automatically executed. So we can write this init function and add some more flags. So here we have the init function and then we typically do Cobra on initialize init config. So this will run this init config. So when Cobra initializes this function will also run where we can then initialize the config. So I'm going to do it very similar as the user guide. We then are going to add to the root cmd a flag. When we use persistent flags, then for every subcommand, this flag will also be available. So for our subcommands, we are going to use local flags that are only available on the subcommand itself. And on our root command, we're going to use a persistent flag that is going to be available for every command because we're going to have this config found. So I'm just going to copy this and add this right here. We will also then need an init config, funk init config and the config file. So this config file is going to be global as well for config file config. And let's then define a config type, which is going to be a struct with a CA cert of type cert CA cert. I'll make it a pointer so that it can also be nil and then YAML CA cert. And this YAML should of course match with this CA cert. Looks like it's matching. We need to do the same for the certificate. And this will be a map, map string cert dot cert. And then the YAML is going to be certs, certs here, the key. And this is going to be the cert object going to save this. So this is a config. So config files of type config init will automatically run, it will say on initialize, run this init config. And this is not going to be a string var. So actually, this is the config file path that we need. So we need another variable config file path is string. And then we will need just a variable config. And we need to parse the contents of this config file path into this config config file path is going to be this one config file path. This is the parameter config, the default value, we can leave it empty and then fill it out ourselves if you want in the init config config file default is and then we can say default is still as a demo. We can also choose that there is a shorter version of config. So if you say string var P, then we will have an extra parameter. We have the name, which is config, but also the shorthand and shorthand can then be C. So we can use either dash dash config or C. Then we need to parse this config file, which is YAML. So if config file path is empty, then we're going to say config path path is T less of YAML. So we can either check for the config file here, or we can input T less of YAML here. So it's the same way you put it. If you're going to check here in the init config, you know that it was not supplied. So you could take other actions like not reading the config file, for example, if it does not supply it. So then the next step is going to be to read the contents of this config file path config file binds is IO read file IO util read file config file path. If there is an error, then we get output that has an error while reading config file. And actually this needs to be print F because we are not returning an error. We're just printing something on screen and then return it. And then we can un-martial into into this config file. So un-martial takes the binds config file binds, and we can marshal this into our config error handling. While parsing the config file, I have one error. And sometimes what happens is that visuals to the code decides to import some random library. It's best to check what library it is importing. This is the one I typically use go get. And now everything is green. So this should pass our config file. And what we can do is we can output it just to see if it worked. Confid called past will then later on remove this. It just to see whether our config file was parsed. Go run. So this is the help flag doesn't seem to be parsing it with the help flag. Let's remove the help flag config file parsed. And this seemed to have worked. Cannot see all the data because it's a pointer. But this would seem to have worked. And this shouldn't happen every time when we execute a command using the command line utility. So whether you want to parse a config every time when you execute it depends on how you want to write this command line utility. If it is empty, you could also say I'm not parsing it. Or you could say I'm trying to parse it. And I will not give an error if there was no config file supplied. And I couldn't read the file. You can also check whether the file exists, for example. It's kind of all up to you how you want to write this command line utility. It should be as natural as possible for the end user without doing crazy things that the user wouldn't expect. I think this is fine. Let's say that you always need a config file. So that when you want to use this tool, you just need to have the last demo in your directory, or you need to supply it with config. So if you say config, my other config demo, then I get an error because the file doesn't exist. So that's how it should work. I can even try with a shorthand flag, the shorthand flag minus C. So that also works. And if I use help, it also shows us the flag. So in the next lecture, what I'm going to do is I'm going to start writing our sub commands. So now I'm going to create the commands and the sub commands. I want to have a create command and some sub commands under this create command. Later, you could then extend this tool with some other commands. Create is what we need for this test server, but maybe we'll also want to read certificates. And you would need an info command. We are just going to focus on this create command. So I am going to create a new file here, create dot go package CMD. And I'm just going to write an init function here. And now I have access to all these global variables here. So I have access to the config, the config file path, but mainly to this root CMD. So if I create a new command, I want to say root CMD, add command. And then I will add a create command. And this create command can be of the same type of Cobra command. So this is going to be my create CMD. And I'm going to import Cobra. And here I can have the same information. Use short and long. And actually, I will delete this run function here, because we don't need to have a run function. When we just execute the root command without anything, use create, create CA certs or keys, commands to create resources, CA certs, keys, save this. And let's see what the behavior now is. Go run main dot go. So now that we don't have a run function, it actually shows the help. So now you have usage, available commands, completion, help, flags. And then we have additional help topics, T last create. But this is going to be another available command, but we haven't written any sub commands yet. So we can already see that it recognizes that we have this create command because create CA certs or keys is actually here in the help. So if you do help, we get the help. If you do create, we just get this create help. Same. So we would need more sub commands. So let's create another sub command for keys, key dot go, package CMD, another init function. Instead of root CMD, we're now going to use create CMD, create CMD add command. And we're going to have a key create CMD key create CMD is going to look similar key create CMD with a cobra command key key commands, commands to create keys. And then we're going to have this run function because now we actually want to do something run, which is a function. And here we can put our code. So let's see if we now use create. Now we get a help create create key key commands. So if you do create key, nothing happens, because this function is still empty. And now if you enter go run without any argument, we see the available commands. Now we have the create command here as well, because now this create command is actually doing something. So it's a real command. We have the create command. We have the config flag, which is global. I'm missing here a bracket. This key command could use a config, but I don't think our key command would need the config. And now we can even add commands at the key level. So what we want to do now, we want to add a key, where do we want to write the key? So we could use a destination key, a destination key as a flag. So we could create a flag within this key. So a flag we can only use in in our create key sub command. So now it is not going to be a persistent flag, it's going to be a normal flag. Key create cmd, flex, string var p, where are we going to store it? Var key out is a string key out and then a name key out, shorthand. So now that we have c already for config, it needs to be something unique. So maybe just k, the value is going to be key dot PEM and the help destination path for key. So now we can write a key code. So how to create a key? Well, we already have this function written create RSA key, and then convert it to a PEM create RSA private key and save. So we could use this search dot create RSA private key and save off these key out. We could even add a flag for the bytes. We could add a flag for the bytes. So the byte length key length called L is cannot be a string. It's an integer, I think an integer key length integer 1496 is a default can choose a default. We are going to make it a default is going to be int var key length, key length and help. And this is going to be cert, cert would be still imported. Looks like it is not being recognized. So go mod copy this pkg cert. And now it is recognized. Not declared cert. It's not going to be cert. It's going to be key make sense. And what does it return an error? If there is an error, then we need to say something, create key error and an error, and then we can return if you want. So let's try that out. This will be our first function. So we have the create. And actually, if I miss type create, that's what is also nice. Did you mean this create? So this is also nice that it has these little things that we don't have to write ourselves. So now we have the last create available commands key, create key. And the length is going to be key length 1496 by default. So we don't really need to supply anything. Create key and nothing has been returned. That's also a little bit awkward. So let's say key created with length. And I need to say key out key length. Save this for the return. And key created key dot BAM with length 1496. Okay, and now you have the key dot BAM. So this is our first sub command key dot go. And now we're going to create another sub command or two other sub commands, CA and cert. And the difference there is going to be that here we already had a function create RSA private key and save. We still need to write a code for the certificates, the CA certificate and the cert. So the Cobra code will be very similar. But then we're actually going to dig into the package cert to be able to generate a CA certificate and then a server certificate. Now that we have finished the key dot go, let's copy paste this key dot go. And then let's create a new file CA dot go. And the CA is going to output two files, the certificate and the key. So we're not going to really use this key dot go anymore. We are not going to separately create a key and then input the key. When we create a CA, we're just going to create a new key. So we're going to have CA key and CA cert. Copy this because they are both going to be a string CA key, CA cert, key out, cert out, CA dot key, and CA cert, destination path for CA key, destination path for CA cert, add CA create CMD to the create command, still a Cobra command, CA, CA commands, commands to create the CA. And we are going to use cert, create CA cert. Oh, this is the string. And what does it need? The config, which should be initialized. So we should have our config in this variable because we did this. So create CA cert config, CA cert. So that comes straight from our config. There's going to be this one here. And then we have the key file path and the CA cert file path, which is the CA key and the CA, CA cert, create CA error, CA created with CA created key cert, and then CA key cert, save this, looks like it's going to work. Clear this. And we have an error. We have the add flag error, because look, I'm still doing key create CMD within the CA. So this is not good. So if you do something like that, you will get an error. And let's try again, available commands CA and key now. And you see the global flags is a config. So we can supply the config when doing the CA command. And that's useful because we have here the config that we parsed. So this is it for the Cobra implementation. Now I will need to do the actual implementation of the creation of the certificate for the CA. So how do we even start with this? So we know that there is an X 509 package X 509. And we are going to create a certificate. So we have X 509 the package. And what does X 509 have create certificates. So now it imported crypto X 509 create certificates, create certificate creates a new X 509 v3 certificate based on a template. The following members of template are currently used. And then there's all the parameters of a template of an X 509 certificate. So what do we need for this? We need an IO reader and we need a template. So why don't we start with creating a template template equals X 509 certificate. And this needs to be a pointer so I'm just gonna make a reference to this. And then what do we need? Serial number Serial number CA Serial because we supply the serial number right here. What else we have valid for years subject subject we also have pkixname is a type. So we will need this one. And this has all these parameters. So we can just supply all these parameters. We just need to make sure because this is a string array that if they were not supplied in the config file they will be empty. So we don't want to return an empty string in a string slice. So let's maybe first make a function. Remove empty string input is a string slice and output is a string slice. And what we are going to do is if length of the input is one because we only have one item in this string. And the first element is empty. Let's then just empty. Let them just return an empty slice. Otherwise, let's return input. Remove empty string or yeah. And then if we then do country, remove empty string. So if our CA subject country would be empty, then it's going to be an empty string. But then this function will remove this empty string by returning an empty slice. So otherwise, it will not show nicely in our certificate. And now basically for every type that we have, because I don't know if I have all the types for every type that we have, we can define these values. So that should work. What else is there? Not before. Not before is of time time. Not before time now, not after time now add and add date. And then we can add some years. Now the only thing that you might want to check is that whether this valid years is not zero or empty. It's an integer. So it will be zero. If this is zero, you probably might want to send to one or you might want to return an error. Not before, not after. What else does it have? Key usage, we should also define extensions, XY extensions is CA also need to say is CA is true. And then I'm going to add this extension key usage is of type extension key usage. And then we need to add some key usage. So this key usage for the CA needs to be five or nine key usage digital center, and actually also the key usage third sign. If you're interested in what exactly these flags mean, besides that they put some constraints, you can have a look in the standards documentation. These bits are actually explained and what exactly that they do. So we are just going to assume these are the ones that we need. And what I'm now going to do is that this create CA cert and this other function create cert can use the same template. So I'm just going to copy this over right here. And the key usage needs to be different here because our server certificate doesn't need this one. But I can now change the CA right here, insert, we'll still need to change this template a little bit. Don't need a CA. But we can now create a common function for these create CA cert and create cert. We just need to make sure that we have all the parameters here as well. I need just one more basic constraints valid indicates where the CA are valid. So if you are using is CA, then we also need this basic constraints valid to true. Let's now try to create a function that can be used by both this create cert function and the create CA cert function. In the next lecture, where we'll do the certification, where we'll finish the create cert, we'll probably make some changes here still. But this is good enough to get an idea. So what would we need to create a function that we can both use for the CA and the cert? So we are going to take this template as an argument. So I call this create cert with a lowercase C. So outside the package, nobody can exit it x five or nine certificates. So I can say template needs to be a pointer x five or nine certificates. What do I need to create the certificates? I will create the private key. But I will for sure also need the CA certificate in case we are going to create a normal certificate and it needs to be signed. So I'm going to pass CA key. That's going to be our say private key and a CA cert. And that's going to be an x five or nine certificate. And because these are pointers, what I can do is if I'm going to create the CA certificate, I don't have the CA key and the CA certificate yet. So I'm just going to pass nil. And what am I going to return? Most likely bytes for the key for the certificate so that we can write it out or use it and an error. So we still have errors because we are not using this template. So let's try to complete our certificate functions. Key binds. Cert binds error is create certificate template. And we are not going to pass a key or a certificate because that's for the create cert. If error is not equal to nil, we're going to return the error. And otherwise we are going to write to a final key bytes and assert bytes. So let's leave it like this for a second so that we can focus on this create cert. Let's see, we'll just leave it like this. And then in the next lecture, we can focus on this. So create cert. What do we need to do? We need to create an RSA key first. We have this function in the key RSA go key key create RSA private key and the bytes and are we passing them? We are not really passing how many bytes so I will just keep it on 1496. What does this return the private key and error? If the error is not equal to nil, we return the error. Now if our template is a CA, we are going to do something different than whether our template is not a CA. So is CA is true? Then we are going to do something else. We are going to do something else. Our certificate is a CA. So we can do X519 create certificate. Rent reader template. The parent. The parent because it's a CA is also the template. The public key. So private key public is a public key. Public key. And the private key and public key also needs to be a pointer. So I'm going to add this ampersand so that it's being sent as a pointer. If you don't do it, then it will just say that it doesn't recognize public key because it's only checking for pointer public keys. What does this return a byte error? We probably want to do a create certificate here as well. So I'm going to create a variable here. Got there bytes. That's a file type that we get back. And error. If error is not equal to nil, return the error. And now we need to just convert it into PAM format because we also want to return it always in PAM format so we can then save it. PAM.go. Could we use this? No, we couldn't use this because this already expected to be in PAM format, but we can use PAM encode instead of decode. So PAM encode. We need to write it somewhere.  So I'm going to have bytes buffer and bytes buffer implements the read and write methods for bytes. So PAM encode, sort out and the PAM block. PAM block that is matching PAM block. What do we need to add here to type optional headers and the bytes. So bytes we have a type is going to be certificate. And the bytes is going to be the bytes. Sort out does not implement IO writer. And that's because bytes buffer implements it as a pointer. So I need to reference it here. And there's an error that returns. So if this error is not equal to no, then we're going to return error. If there's no error, then it will have taken this PAM block with the certificate type with the bytes. And it will have written it to sort out. We can do the same for the RSA private key. So if we make a key out bytes buffer changes into key out PAM block. And I think we have a function here RSA private key to PAM. And this is returning this PAM block type RSA private key. And then it's going to marshal this private key into bytes. So we can use this instead of the PAM block key. And then the private key. And this should also work. So we have a certificate private key. And insert out and key out we now have the bytes PAM encoded. So we can just return it now. Set out bytes. What does bytes return bytes key out. Maybe I'll put a key first. I think I always put the key first. So if you put a key first, we should always put the key first. No errors. But we only did the CA obviously. And now we can have key out here key bytes. And we can write this to a file. Key bytes and sort bytes. IO utl write file file name, which was supplied key file path, the data key bytes, and the permissions for the key is going to be 0 600. What does it return an error? If error is not equal to nil, going to return error. And we're going to do the same for the cert bytes. And the cert bytes can actually be 644. Because RCA certificate can be public. So it doesn't need to have these extra permissions. It's just for your local machine just to make sure that nobody else can read it accidentally. It's kind of best practice to have your key always written with no group or other reads permissions, cert file path, CA cert file path, and cert bytes. Save this. And let's hope that it all works. Only one way to know go run. That's where see whether it compiles. Okay, available command is the CA. So we do help not sure that they're gonna work minus H unable to redefine C. Okay, because we already have the config. See there is already a C here for the config.  So if you want to supply a config file, we don't need to really supply anything, then it will take the default CA key CA cert. And that created everything. I just need another return here. How can we validate this? Well, we can actually use the open SSL utility, open SSL in CA cert, text no out, I think that it is. And if you don't have the open SSL utility, you can either download it, or you can also validate online, there's tools online, if you type open SSL, read certificate, there are websites where you can paste your certificate and it will show the output for you. You can do this with the certificate, but don't do this with a key, because the key you should keep secret. This was not a command. Open SSL X 509. It is because it's of X 509 type. And this shows that in text, everything serial number one. So that was good. Not before and not after there's 10 years in between. So that's also good. The issuer is the same as the subject. Because it's our self signed CA country US locality New York organization, go like demo organization, organizational unit certificate management and common name CA certificate. Then we also should have these extensions. The CA is true. Digital signature certificate sign, web client application that all looks good. So I think we now have our CA created. And now we can use this CA, the CA key to sign our service certificate. So in next lecture, I will create a service certificate and have it signed by our CA. So let's go back to our X 509.go. And here we have this create server that we didn't finish template, serial number. We have the country, the common name, the common name. But we also need to add DNS name. Not before, not after. Let's see if you just have DNS name DNS names. It's also a string. So if it's empty, then we return empty string. If it's not empty, then it should just be the DNS names. Third subject or third. Oh, I think we are not parsing this. Where is our types? Yes, we can add it here. DNS names. It's a string DNS names. And then here DNS names. What else do we need to do? We need to parse the CA key and CA cert and then pass it to this create cert function key and private key PEM2RSA. Yeah, that's the one CA key. And it's going to return as the private key because we need the private key to be able to sign. This returns an error. So we have the CA private key and the error. If there's an error, return error. And then we have the CA certificates. And for that we have in PEM.go, PEM2X599 CA cert, parsed, CA key, parsed. So let's now just copy this, the template, the X5NN certificate, and then the CA key and the CA cert, CA key parsed, CA cert parsed. And then we're going to write the key file path and the cert file path. So we're still going to write the server key and the server cert based on what we get back. Save this. And then we just need to make sure that if it's not a CA, that we also have some code, create certificates. The parent in this case is going to be the CA cert. And the private key is then going to be the CA private key. Because to sign a certificate, we need the CA private key. Save this. This is going to create the certificate. And then we just need to make sure that we have the code in our CMD for the cert. I can copy paste most of the stuff from the CA.go. So that's what I'm going to use. Cert key and cert, cert key, cert. Oh, cert is already declared. So I'm just going to call this path at the end. Cert path. So this shouldn't really give us an issue because those are local flags. But now we also need the CA key and certificate. So let me just change this, create CMD cert, CMD. And then this needs to be cert, CMD, cert, cert commands, commands to create the certificates. And then we're going to have a create cert. And we also need to supply the CA key and the CA cert. So this is going to be cert key path and cert path. But then in between we have these two still to add. Create cert error, cert created, cert key path. Okay, I think we have everything, but we need to ask the user for a few things. We need to know the CA certificate and the CA key, but also the certificate name. So cert name, that's going to be another flag. Cert name, or just name with N, what is going to be the default? That's not going to be a default. Name of the certificate in the config file. And then we also need, let me just maybe copy paste it from here, and cert, CA key and CA cert. And maybe let's not give them shorthand flags, might be confusing a bit. Defaults, CA key and CA cert. Yes, why not? Is the CA key to sign certificate, CA cert. Which ones are mandatory now? Well, those three are not mandatory. So we can say cert create CMD, mark flag required, name, mark flag required, CA key is required, CA cert is required, and the name is required. And then I have to pass the CA key, but it needs to be in bytes. So I need to pass it first. CA key binds error is IO util read file of this CA key. If the error is not equal to nil, CA key error, and we'll have to stop. And we are going to do the same for CA cert, read the CA cert, CA cert error, read error and read error, we'll call it. And we can add the CA key binds and the CA cert binds. Save this. We still get an error, no new variables on left side. Config CA cert that's now going to be something else. So we still have to say cert config. Okay, is config cert, which is the map. And we have the name cert name. So you're asking for the name, we checking in this map whether this key exists. If this key exists, okay, it'll be true. If okay is not true, then we're gonna say, could not find certificate name in config, and we'll stop. And this should be done the cert. And that is a cert. All right, will this work? Hopefully. Maybe I made a mistake somewhere, but then we'll find it out very quickly. If this doesn't work, go run create cert, because it's called cert error required flags CA cert CA key and name not set. So that works pretty nice. And then we have this flag that we can set. So let's add these flags. The name is this key here, go demo local test me CA key is CA dot key and CA cert is CA cert could not find certificate name in config, cert name, cert name here, string var, probably did something wrong. Sort path, which would be sort name. Because that's a name, cert created key is cert key and sort is cert cert. Let's do the same with this open SL utility on our cert cert. And actually, I didn't want to call it cert cert. I wanted to call it server dot cert and server dot key. So let me just run it again, because that's how we put it in our test server, I think server dot CRT. Okay, server dot CRT is created. Open SSL utility on server dot CRT seems to work serial number one issuer is our CA certificate. And the subject is this code demo. One year valid. You have these extensions, and we have these alternative names. Right, right. Let's try to run our test server. And it's going to run on 443. Let's try first maybe to use the browser. Port 80. This side can be reached. I'm going to add HPS. And then it says your connection is not private. Because our certificate authority invalid, it doesn't know about our certificate authority, the CA certificate that is being issued. And that is because we self signed our certificate, because I was explaining that our browser knows about our root certificate, but not about our issuer CA certificate that we created ourselves. So we need to add this CA certificate to every client that we are going to use. Some clients can do it easily. Some clients cannot. But you see that there is a reason why you should use a root certificate for a public website, or let's encrypt and that a self signed certificate will not work. If you are not a client, it still works for development purposes, because I can do advanced. And I can do proceed. And then I get it's working, but I will still get this not secure because the CA cannot be validated. So let's try to do it with curl. And let's see if we can have the CA validated. And if we can have the CA validated, then we should not get an error curl, unable to get a local issuer. Now let's try curl with CA certificate CA CRT. So we are now supplying the CA certificate to our client curl. And then it will be able to use the CA certificate to see if our service certificate is valid. And actually, I get another error, no alternative certificate subject names matches. And that's because I should probably have not only the common name here, so either you use not DNS names, and then it will just work on the common name, or I need to make sure that I define everything in DNS names. So I'm going to save this. And then I will have to reissue my certificate. Let's run this open as well tool again. And then I see subject alternative names. Now I have both of them. And let's try now. Again, connection refused because I didn't start it. Go run testing the and now it does it's working. So only when you supply the CA certificate, only when you supply this argument CA cert, then it will be able to validate it. Because now if you do curl without it, it only has the root certificates from somewhere a directory on our operating system, where we have all these root certificates, but we are not using a root certificate, we are using a self signed certificate, which we then need to supply with CA cert. So in your browser, you could also make it work by importing this CA certificate. It's not really recommended on your browser to use every day to start importing certificates. So in general, if you are going to work with a server, then you should use let's encrypt or root certificates. It's for testing, or it can still be in production when you can supply your own CA certificate, or in companies that manage every browser on every machine, they also sometimes inject their own CA. It's also useful for 280 less, as I explained earlier with 280 less, you can have your CA bundled with your client and your server, and then you can also verify it. So this is the end of the demo. I hope that this whole certificate CA has been useful. It teaches you not only how to do it in Go, but also shows you in much detail how this signing and validating works, and what really the process is when connecting to a secure website. Now that we have our test server running with our self signed certificates, let's now investigate how we would run our test server with a let's encrypt certificate. Let's encrypt is different because let's encrypt can sign using a root certificate, a root certificate that is recognized by your browser or by curl. So we don't need to import the CA certificate to be able to validate the server certificate. Even though let's encrypt signs with the root certificate, it was still useful to explore self signed certificates, because it's also useful for two way TLS. And like I explained in the previous lecture, there are different scenarios where self signed certificates are preferred. Let's try to create another server or let's encrypt server. And in this let's encrypt server, let's make a new main dot go package main. And let's copy paste from our previous lecture. And what we are going to do different now is we're going to use auto cert. Auto cert is a package provided by go. So we need to do a go get first go lang.org x so it's extra packages crypto acme this protocol that is being used by let's encrypt and auto cert. And this package contains helper functions to integrate within our HP package, the automatic certification. So we will not have to do much we will just have to add this auto cert to our TLS server. And then it will create a renew packages for us. So let's have another look at this process. So this is the schematic. What needs to happen is that we need to support this acme. So our auto cert package will implement this acme which is in a separate package. And it will create this well known URL with this token to be able to verify our server. Let's encrypt will then know that we own this domain and will issue a server certificate that we can use. So that is what all happens in the background. The only thing that we need to do is to import this auto cert, copy our code. And we're then going to change the listener serve into just serve. And serve will then ask for a listener and net listener. And this net listener is implemented by this auto cert. So this auto cert has a new listener. And we can just apply domains which needs to be a real domain. So if you want to test out this demo yourself, you will have to register a domain or use a domain that you already have. My name is registered by Namecheap.com. And Namecheap gives you a DNS panel where you can add records to point a DNS name to a server. So it's an in a DNS record. And I'm running a VM on digital ocean. But you can really run a VM anywhere. And I'll have to then copy this binary, this goal binary that I will create here to my digital ocean VM. So the domain name is go demo test new tech academy. So if I try to resolve this, host go demo test, this goes to my VM. So you need to have this setup first. And then what I'm going to do is I'm going to copy this binary to this VM, run this on this VM, and see if I will get the certificate issued by let's encrypt. So once this code gets executed, it will serve on for for three. So I just have to curl to for three. This new listener of auto search will then go to let's encrypt and ask to issue the certificates. So new listener is convenience function for common configuration. You can also do more complex configurations by using the auto search manager type. Also important certificates are cashed in the golden auto search directory. So it's not going to issue a new search every time it will create a demo directory and you will find your key and insert in there. So this should be it really. Let's try to build it. Go build. Let's encrypt server. And my server is a Linux server. So I will need to also specify that I want to build this for Linux.  And I will compile CMD let's encrypt server main.go. Then I will copy this over to my test server, SCP. I will need to specify my SSH key root code demo test. And the source file is let's encrypt server. Now I will have to start this binary on the VM. Now I'm logged into the VM. And I can start it using let's encrypt server. And let me now create a new window. And I'm just going to go to this website. Go demo test new tech academy. And if everything is working, I should get that it's working. It's working. So no CA certificate warnings. A new certificate has been issued, which is now a let's encrypt TLS certificate. So if I try this in a browser, HTTPS. Go demo test. The HP will not work because we didn't open anything on port 80, but you could actually add something on port 80 that just will forward to HTTPS. And if we now click here, connection is secure. Certificate is valid. And it is a let's encrypt certificate that has been issued. And this is valid. So if you are doing one way TLS, and you need your server to be accessible to everyone on the internet, then the easiest way to do that without having to buy a TLS certificate from one of these known companies is to use let's encrypt. And you see that it's very easy to integrate it within your go program. What happened in the background is that go did this ACME validation for you in this auto set package that's code to that for you. And if you then go back to the VM, I will see these errors as well. It just other people like bots trying to make connections, but we only whitelist this domain name. So we'll only ask a certificate for this hostname, not for any hostname that people are trying to access. So if we now have a look here in the dot cash directory, there's a golden auto cert directory. And here we have our certificate. Go demo tests, new tech Academy is our certificate. And this is our key. So here's our certificate that has been issued. So this is it for this demo. It's just a very small change to have in go a let's encrypt certificate issued and use it with a TLS listener. I have shown you how to start a server using a self signed certificate. I've shown you how to use a let's encrypt certificate. Now let's try to create a server that is two way TLS. So any client connecting to our server will also need a client certificate. This is what I explained in one of the previous lectures, the mutual TLS diagram.  And the client is then going to connect using TLS to the server. The server will need to be reconfigured a little bit. The server is only allowed to accept clients if they have a client certificate. So the server will also have to validate the certificate authority certificate. So we also need to supply this CA cert to the server. Again, this is not very different than our test server. So let's start again with our test server. Let's create directory empty less server and then we'll have an empty less client main.go. So